2010-02-24 21 views
7

içine açılan dosyalar akışlarına bir .rar dosyasında dosyaları ayıklamak mümkün olduğunu. unrar source'u nasıl kullanacağımı anlamak için bir test vakası oluşturuyorum. Bir süredir araştırıyor ve tamir ediyordum ama kütüphaneyi nasıl kullanacağımı anlayamıyorum. .rar arşivlerinin ne kadar yaygın olduğunu göz önünde bulundurarak, bunun için bir belge veya öğretici bile bulamıyorum.- İhtiyacım Ne filestream tampon

başıma ilerleme biraz yaptık, ama her zaman çalışmıyor. Bazı dosyalar düzgün şekilde ayıklanır. Diğer dosyalar bir nedenden dolayı karıştırılmıştır (ancak tamamen "çöp" ikili verileri değil). Tüm bildiğim şu ana kadar deyişle, genellikle (ama her zaman değil):

  • çalışmıyor dosyalar fileInfo.Method = 48 var. Bunlar% 100'lük bir sıkıştırma oranına sahip olduğu dosyaları görünür - fileInfo.Method = 49, 50, sıkıştırma hızları karşılık 51, 52 veya 53, En Hızlı, Hızlı, Normal, İyi

  • çalışan dosyalar var hiçbir sıkıştırma yani bu yüzden, en iyi

Ama hiçbir fikrim yok. Hala belge veya çalışma örneği bulamıyor.

Aşağıda ben bugüne kadar test durumu kaynağı ve bu program ile çıkarıldığında, her iki çalışma, çalışmayı ve dosyaları olan bir example rar archive olduğunu.

/* 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; 

} 

güncelleme: Ben gibi görünen (? Olduğunu iddia) documentation bir dosya buldum ama dosyaya göre, yanlış bir şey yapmıyorum

. Bence, CRC'yi arabellekleri kontrol etmek ve başarısız olursa bir geçici çözüm uygulamak için başvurmak zorunda kalabilirim.

çözüm kaynağı (teşekkürler Denis 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

Belki EOL karakterleri (arşiv Unix üzerinde Windows üzerinde yapılan ancak çıkarılan) ile ilgili bir sorun, ama emin değilim .. –

+0

okurken ben fileSize' '' Doğru buffLen' veya kullandığınızdan emin yapıyorum/arabelleklere yazıyor olsa da. Bu noktada, suçu sadece unrar kütüphanesine koymaya hazırım. – Kache

cevap

6

Ben, unrar ile familar değilim. Ancak, bence unrar bunu defalarca çağırabilir. Daha sonra bazı verileri açar CallbackProc çağırır, sonra bir sonraki veri yığın açar ve tekrar tüm veriler işlenir kadar işlem tekrarlanır, CallbackProc çağırır. Aslında arabelleğe almak için kaç bayt yazıldığını ve karşılık gelen ofsetle yeni verilerin ekleneceğini unutmayın.

+0

Hatalı çıkarılan dosyaların neden tüm çöp verilerinin toplanıp karıştırılmadığını kesinlikle açıklıyor. Dokümantasyonu tekrar okudum ve dosya adının, dosya başına geri çağırma işlemini birden çok kez yürütebileceği izlenimi vermedi. Bunu nasıl düşündün? Çıkarma işleminin ortasında periyodik olarak yürütme çağrısı yapmak bana çok sezgisel gelmiyor. – Kache

+0

Sanırım bunun nedeni, arşivdeki dosyaların yeterince büyük olabileceği ve kullanılabilir belleğe sığmayacağıdır. Bu dosyaları tamamen bir arabelleğe açmak imkansız veya en azından verimsiz olacaktır. –

0

görünüyorsunuz bazı kaynak-kod, ama hiçbir gerçek soru gönderdiniz etmek. This Article

+0

Derlemek için (boş bir ana() ') bile alamıyorum. Bir rar arşivindeki bir dosyayı, istediğim gibi yapmak için arabelleğe sıkıştırmaya çalışıyorum. Bağlantılarına baktım. Rarlabs'ın bildiğim unrar kütüphanesi için bir desteği yok - sadece açık kaynak kodlu bir unrar kütüphanesi. – Kache

3

Ben de çevrimiçi hiçbir dokümana bulamıyorum, ancak kullanabilirsinizörnekler vardır:

göremez, (Ayrıca kendi forums

işaret hangi Rarlabs Feedback Page bakarak düşündünüz mı:

http://www.krugle.com adresine gidin ve sayfanın sol alt köşesinde, RAROpenArchiveEx gibi bir anahtar kelime girin, çeşitli açık kaynak kodlu projektörlerden başlık ve kaynak dosyaları göreceksiniz. unrar kütüphanesinden yararlanır. Gidiyor almalısınız

. Bir belgeleri hızlı okuma sana CallbackProc tam olarak bir kez dosya başına denir varsayarak düşünüyorum sonra

+0

Teşekkürler! Bunlardan bazılarına göz atacağım. Umarım bu özlerden en az biri doğrudan bir tampona çıkar ve ben de aynı şeyi nasıl yapacağımı anlayabilirim. – Kache