में फ़ाइलों को निकालने के लिए मुझे एक .rar फ़ाइल में फ़ाइलों को स्ट्रीम में निकालने में सक्षम होना चाहिए। मैं unrar source का उपयोग करने का तरीका समझने के लिए एक टेस्ट केस बना रहा हूं। मैं थोड़ी देर के लिए खोज और tinkering रहा है, लेकिन मैं पुस्तकालय का उपयोग करने के बारे में पता नहीं लगा सकता। मुझे आश्चर्य है कि मैं इस बात पर विचार कर रहा हूं कि यह कितना आम है। आरआर अभिलेखागार हैं।अनार लाइब्रेरी का उपयोग करना - फाइलस्ट्रीम बफर
मैंने अपने आप पर कुछ प्रगति की है, लेकिन यह हमेशा काम नहीं करता है। कुछ फाइलें ठीक से निकाली जाती हैं। अन्य फाइलें किसी कारण से जुड़ी हुई हैं (लेकिन पूरी तरह से "कचरा" बाइनरी डेटा नहीं है)। सभी मैं जानता हूँ कि अब तक है, आम तौर पर (लेकिन हमेशा नहीं):
काम नहीं कर फ़ाइलें
fileInfo.Method = 48
है। वे दिखाई देते हैं 100% की एक संपीड़न अनुपात है कि फ़ाइलें होने के लिए - कोई संपीड़नकाम कर रहे हैं, आप IE फ़ाइलों
fileInfo.Method = 49
,50
,51
,52
, या53
, जो संपीड़न गति के अनुरूप है, सबसे तेज, फास्ट, सामान्य, अच्छा , बेस्ट
लेकिन मुझे नहीं पता कि ऐसा क्यों है। अभी भी दस्तावेज़ीकरण या एक कामकाजी उदाहरण नहीं मिल रहा है।
नीचे परीक्षण केस स्रोत है जो अब तक है और example rar archive है कि, जब इस प्रोग्राम के साथ निकाला जाता है, तो दोनों काम कर रहे हैं और काम नहीं कर रहे हैं।
/* put in the same directory as the unrar source files
* compiling with:
* make clean
* make lib
* g++ rartest.cpp -o rartest libunrar.so -lboost_filesystem
*/
#include <cstring>
#include <iostream>
#include <fstream>
#include <boost/filesystem.hpp>
#define _UNIX
#define RARDLL
#include "dll.hpp"
using namespace std;
namespace fs = boost::filesystem;
//char fileName[100] = "testout0.jpg\0";
//
//// doens't work
//int PASCAL ProcessDataProc(unsigned char* buffer, int buffLen) {
// cout << "writing..." << endl;
// ofstream outFile(fileName);
// cout << buffLen << endl;
// cout << outFile.write((const char*)buffer, buffLen) << endl;
// cout << "done writing..." << endl;
// fileName[7]++;
//}
int CALLBACK CallbackProc(unsigned int msg, long myBuffer, long rarBuffer, long bufferLen) {
switch(msg) {
case UCM_CHANGEVOLUME:
break;
case UCM_PROCESSDATA:
memcpy((char*)myBuffer, (char*)rarBuffer, bufferLen);
break;
case UCM_NEEDPASSWORD:
break;
}
return 1;
}
int main(int argc, char* argv[]) {
if (argc != 2)
return 0;
ifstream archiveStream(argv[1]);
if (!archiveStream.is_open())
cout << "fstream couldn't open file\n";
// declare and set parameters
HANDLE rarFile;
RARHeaderDataEx fileInfo;
RAROpenArchiveDataEx archiveInfo;
memset(&archiveInfo, 0, sizeof(archiveInfo));
archiveInfo.CmtBuf = NULL;
//archiveInfo.OpenMode = RAR_OM_LIST;
archiveInfo.OpenMode = RAR_OM_EXTRACT;
archiveInfo.ArcName = argv[1];
// Open file
rarFile = RAROpenArchiveEx(&archiveInfo);
if (archiveInfo.OpenResult != 0) {
RARCloseArchive(rarFile);
cout << "unrar couldn't open" << endl;
exit(1);
}
fileInfo.CmtBuf = NULL;
cout << archiveInfo.Flags << endl;
// loop through archive
int numFiles = 0;
int fileSize;
int RHCode;
int PFCode;
while(true) {
RHCode = RARReadHeaderEx(rarFile, &fileInfo);
if (RHCode != 0) break;
numFiles++;
fs::path path(fileInfo.FileName);
fileSize = fileInfo.UnpSize;
cout << fileInfo.Method << " " << fileInfo.FileName << " (" << fileInfo.UnpSize << ")" << endl;
char fileBuffer[fileInfo.UnpSize];
// not sure what this does
//RARSetProcessDataProc(rarFile, ProcessDataProc);
// works for some files, but not for others
RARSetCallback(rarFile, CallbackProc, (long) &fileBuffer);
PFCode = RARProcessFile(rarFile, RAR_TEST, NULL, NULL);
// properly extracts to a directory... but I need a stream
// and I don't want to write to disk, read it, and delete from disk
//PFCode = RARProcessFile(rarFile, RAR_EXTRACT, ".", fileInfo.FileName);
// just skips
//PFCode = RARProcessFile(rarFile, RAR_SKIP, NULL, NULL);
if (PFCode != 0) {
RARCloseArchive(rarFile);
cout << "error processing this file\n" << endl;
exit(1);
}
ofstream outFile(path.filename().c_str());
outFile.write(fileBuffer, fileSize);
}
if (RHCode != ERAR_END_ARCHIVE)
cout << "error traversing through archive: " << RHCode << endl;
RARCloseArchive(rarFile);
cout << "num files: " << numFiles << endl;
}
अद्यतन:
मैं एक फ़ाइल प्रतीत होता है (? होने का दावा) documentation कि मिल गया है, लेकिन फाइल के अनुसार, मैंने कुछ गलत नहीं कर रहा हूँ। मुझे लगता है कि मुझे सीआरसी को बफर की जांच करने और अगर विफल होने पर कामकाज को लागू करने के लिए मजबूर होना पड़ सकता है।
समाधान स्रोत (धन्यवाद, डेनिस Krjuchkov!):
/* put in the same directory as the unrar source files
* compiling with:
* make clean
* make lib
* g++ rartest.cpp -o rartest libunrar.so -lboost_filesystem
*/
#include <cstring>
#include <iostream>
#include <fstream>
#include <boost/filesystem.hpp>
#include <boost/crc.hpp>
#define _UNIX
#define RARDLL
#include "dll.hpp"
using namespace std;
namespace fs = boost::filesystem;
//char fileName[100] = "testout0.jpg\0";
//
//// doens't work
//int PASCAL ProcessDataProc(unsigned char* buffer, int buffLen) {
// cout << "writing..." << endl;
// ofstream outFile(fileName);
// cout << buffLen << endl;
// cout << outFile.write((const char*)buffer, buffLen) << endl;
// cout << "done writing..." << endl;
// fileName[7]++;
//}
int CALLBACK CallbackProc(unsigned int msg, long myBufferPtr, long rarBuffer, long bytesProcessed) {
switch(msg) {
case UCM_CHANGEVOLUME:
return -1;
break;
case UCM_PROCESSDATA:
memcpy(*(char**)myBufferPtr, (char*)rarBuffer, bytesProcessed);
*(char**)myBufferPtr += bytesProcessed;
return 1;
break;
case UCM_NEEDPASSWORD:
return -1;
break;
}
}
int main(int argc, char* argv[]) {
if (argc != 2)
return 0;
ifstream archiveStream(argv[1]);
if (!archiveStream.is_open())
cout << "fstream couldn't open file\n";
// declare and set parameters
RARHANDLE rarFile; // I renamed this macro in dll.hpp for my own purposes
RARHANDLE rarFile2;
RARHeaderDataEx fileInfo;
RAROpenArchiveDataEx archiveInfo;
memset(&archiveInfo, 0, sizeof(archiveInfo));
archiveInfo.CmtBuf = NULL;
//archiveInfo.OpenMode = RAR_OM_LIST;
archiveInfo.OpenMode = RAR_OM_EXTRACT;
archiveInfo.ArcName = argv[1];
// Open file
rarFile = RAROpenArchiveEx(&archiveInfo);
rarFile2 = RAROpenArchiveEx(&archiveInfo);
if (archiveInfo.OpenResult != 0) {
RARCloseArchive(rarFile);
cout << "unrar couldn't open" << endl;
exit(1);
}
fileInfo.CmtBuf = NULL;
// cout << archiveInfo.Flags << endl;
// loop through archive
int numFiles = 0;
int fileSize;
int RHCode;
int PFCode;
int crcVal;
bool workaroundUsed = false;
char currDir[2] = ".";
char tmpFile[11] = "buffer.tmp";
while(true) {
RHCode = RARReadHeaderEx(rarFile, &fileInfo);
if (RHCode != 0) break;
RARReadHeaderEx(rarFile2, &fileInfo);
numFiles++;
fs::path path(fileInfo.FileName);
fileSize = fileInfo.UnpSize;
crcVal = fileInfo.FileCRC;
cout << dec << fileInfo.Method << " " << fileInfo.FileName << " (" << fileInfo.UnpSize << ")" << endl;
cout << " " << hex << uppercase << crcVal << endl;
char fileBuffer[fileSize];
char* bufferPtr = fileBuffer;
// not sure what this does
//RARSetProcessDataProc(rarFile, ProcessDataProc);
// works for some files, but not for others
RARSetCallback(rarFile, CallbackProc, (long) &bufferPtr);
PFCode = RARProcessFile(rarFile, RAR_TEST, NULL, NULL);
// properly extracts to a directory... but I need a stream
// and I don't want to write to disk, read it, and delete from disk
// PFCode = RARProcessFile(rarFile, RAR_EXTRACT, currDir, fileInfo.FileName);
// just skips
//PFCode = RARProcessFile(rarFile, RAR_SKIP, NULL, NULL);
if (PFCode != 0) {
RARCloseArchive(rarFile);
cout << "error processing this file\n" << endl;
exit(1);
}
// crc check
boost::crc_32_type crc32result;
crc32result.process_bytes(&fileBuffer, fileSize);
cout << " " << hex << uppercase << crc32result.checksum() << endl;
// old workaround - crc check always succeeds now!
if (crcVal == crc32result.checksum()) {
RARProcessFile(rarFile2, RAR_SKIP, NULL, NULL);
}
else {
workaroundUsed = true;
RARProcessFile(rarFile2, RAR_EXTRACT, currDir, tmpFile);
ifstream inFile(tmpFile);
inFile.read(fileBuffer, fileSize);
}
ofstream outFile(path.filename().c_str());
outFile.write(fileBuffer, fileSize);
}
if (workaroundUsed) remove(tmpFile);
if (RHCode != ERAR_END_ARCHIVE)
cout << "error traversing through archive: " << RHCode << endl;
RARCloseArchive(rarFile);
cout << dec << "num files: " << numFiles << endl;
}
शायद ईओएल वर्णों (विंडोज़ पर किए गए संग्रह लेकिन यूनिक्स पर निकाले गए संग्रह) में कोई समस्या है, लेकिन मुझे यकीन नहीं है .. –
मैं पढ़ते समय सही 'buffLen' या' फ़ाइल आकार 'का उपयोग करना सुनिश्चित कर रहा हूं/हालांकि बफर को लिखना। इस बिंदु पर, मैं सिर्फ अनार पुस्तकालय पर दोष लगाने के लिए तैयार हूं। – Kache