2010-02-24 12 views
7

में फ़ाइलों को निकालने के लिए मुझे एक .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; 

} 
+0

शायद ईओएल वर्णों (विंडोज़ पर किए गए संग्रह लेकिन यूनिक्स पर निकाले गए संग्रह) में कोई समस्या है, लेकिन मुझे यकीन नहीं है .. –

+0

मैं पढ़ते समय सही 'buffLen' या' फ़ाइल आकार 'का उपयोग करना सुनिश्चित कर रहा हूं/हालांकि बफर को लिखना। इस बिंदु पर, मैं सिर्फ अनार पुस्तकालय पर दोष लगाने के लिए तैयार हूं। – Kache

उत्तर

6

मैं प्रलेखन के त्वरित पढ़ने के बाद अनार के साथ familar नहीं हूँ, मुझे लगता है कि आप मानते हैं कि CallbackProc प्रति फ़ाइल ठीक एक बार कहा जाता है। हालांकि, मुझे लगता है कि अनार इसे कई बार कॉल कर सकता है। यह कुछ डेटा अनपैक करता है तो CallbackProc पर कॉल करता है, फिर अगले डेटा खंड को अनपैक करता है और फिर CallbackProc पर कॉल करता है, प्रक्रिया तब तक पुनरावृत्त होती है जब तक कि सभी डेटा संसाधित नहीं हो जाते। आपको याद रखना चाहिए कि बफर में वास्तव में कितने बाइट लिखे गए हैं, और संबंधित ऑफसेट पर नए डेटा को जोड़ना है।

+0

यह निश्चित रूप से बताता है कि विफल निकाली गई फ़ाइलों को क्यों झुकाया गया था लेकिन सभी कचरा डेटा नहीं। मैंने प्रलेखन को दोबारा पढ़ा, और इससे मुझे कोई इंप्रेशन नहीं मिला कि अनारर प्रति फ़ाइल कई बार कॉलबैक निष्पादित कर सकता है। आप इसके बारे में कैसे सोचते थे? निष्कर्षण के बीच में समय-समय पर कॉलबैक निष्पादन करना मेरे लिए बहुत सहज नहीं लगता है। – Kache

+0

मुझे लगता है कि कारण यह है कि संग्रह में फ़ाइलें पर्याप्त रूप से बड़ी हो सकती हैं और उपलब्ध स्मृति में फिट नहीं होतीं। ऐसी फ़ाइलों को पूरी तरह से एक बफर में अनपॅक करना असंभव या कम से कम अक्षम होगा। –

0

आप लग रहे कुछ स्रोत-कोड, लेकिन कोई वास्तविक प्रश्न पोस्ट की है। This Article

+0

मुझे संकलित करने के लिए (यहां तक ​​कि खाली 'मुख्य() ') नहीं मिल सकता है। मैं एक बफर में एक रार संग्रह में एक फ़ाइल को असम्पीडित करने की कोशिश कर रहा हूं, जैसा कि मेरी इच्छा है। मैंने आपके लिंक देखे। रारलाब्स के पास उनके अनार पुस्तकालय के लिए कोई समर्थन नहीं है, जिसे मैं जानता हूं - बिना किसी दस्तावेज के खुली सोर्स वाली अनार लाइब्रेरी। – Kache

3

मैं कोई भी दस्तावेज़ ऑनलाइन नहीं मिल सकता है या तो है, लेकिन वहाँ उदाहरण आप उपयोग कर सकते हैं:

आप (जो उनके forums

इसके अलावा के लिए अंक Rarlabs Feedback Page को देखकर माना जाता है, को देखने के लिए कहें:

http://www.krugle.com पर जाएं, और पृष्ठ के निचले बाएं कोने में, RAROpenArchiveEx जैसे कीवर्ड दर्ज करें। आपको विभिन्न ओपन सोर्स प्रोजेक से हेडर और स्रोत फाइलें दिखाई देगी टीएस जो अनार पुस्तकालय का उपयोग करते हैं।

आपको यह जाना चाहिए।

+0

धन्यवाद! मैं इनमें से कुछ के माध्यम से एक नज़र रखना होगा। उम्मीद है कि कम से कम इनमें से एक निष्कर्ष सीधे एक बफर के लिए है, और मैं यह समझ सकता हूं कि एक ही चीज़ कैसे करें। – Kache

संबंधित मुद्दे