7
votes

Utilisation d'une bibliothèque UNAR - extraire des fichiers dans un tampon filtream

Ce dont j'ai besoin est de pouvoir extraire les fichiers dans un fichier .rar dans des flux. Je crée un cas de test pour avoir un sentiment d'utilisation d'utiliser Source . Je cherche et je bricole pendant un moment, mais je ne peux pas comprendre comment utiliser la bibliothèque. Je suis surpris que je ne puisse même pas trouver de documentation ou un tutoriel pour cela, en considérant à quel point les archives communes sont communes.

J'ai fait un peu de progrès tout seul, mais cela ne fonctionne pas toujours. Certains fichiers sont extraits correctement. D'autres fichiers sont jumblés pour une raison quelconque (mais pas complètement em> les données binaires "ordures"). Tout ce que je sais jusqu'à présent, c'est généralement (mais pas toujours): p>

  • ne fonctionne pas les fichiers de travail ont fileinfo.method = 48 code>. Ils semblent être des fichiers qui ont un ratio de compression de 100% - c'est-à-dire aucune compression p> li>

  • Les fichiers de travail ont fileinfo.method = 49 code>, 50 code>, 51 code>, 52 code>, ou 53 code>, qui correspond à la vitesse de compression, le plus rapide, rapide, normal, bon, meilleur p> li> ul>

    Mais je ne sais pas pourquoi c'est. Ne peut toujours pas trouver de la documentation ou un exemple de travail. P>

    ci-dessous est la source de test de test que j'ai jusqu'à présent et un Exemple Archive RAR qui, lorsqu'il est extrait avec ce programme, a à la fois des fichiers fonctionnant et ne fonctionne pas. p> xxx pré>

    mise à jour: p> J'ai trouvé un fichier qui semble être (prétend être?) Le Documentation , mais selon le fichier, je ne fais rien de mal. Je pense que je pourrais être obligé de recourir à CRC en train de vérifier les tampons et de mettre en œuvre une solution de contournement s'il échoue. P>

    Source de solution (merci, Denis Krjuchkov!): P>

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


2 commentaires

Peut-être qu'il y a un problème avec les caractères EOL (Archive faite sur Windows mais extraite sur UNIX), mais je ne suis pas si sûr ..


Je m'assonne à utiliser le bon bufflen ou FileSize lors de la lecture / de l'écriture sur les tampons. À ce stade, je suis prêt à simplement mettre le blâme sur la bibliothèque d'UNRAR.


3 Réponses :


0
votes

Vous semblez avoir posté du code source, mais pas de question réelle.

Avez-vous envisagé de regarder Page de rétroaction RARLABS (qui pointe vers leur forums

Aussi, voir: Cet article


1 commentaires

Je ne peux pas obtenir (même un principal () ) pour compiler. J'essaie de décompresser un fichier dans une archive RAR dans un tampon, à faire avec comme je le souhaite. J'ai parcouru vos liens. Rarlabs n'a pas de soutien à leur bibliothèque d'UNRARD que je connaisse - juste une bibliothèque d'irrécouvrable ouverte sans documentation.



3
votes

Je ne trouve aucune DOCS en ligne non plus, mais il y a exemples vous pouvez utiliser:

aller à http://www.krugle.com , et dans le coin inférieur gauche de la page , entrez un mot clé comme rarropenarchiveex . Vous verrez des fichiers d'en-tête et de sources de divers projets open source qui utilisent une bibliothèque d'UNRAR.

cela devrait vous faire aller.


1 commentaires

Merci! Je vais jeter un coup d'oeil à travers certains d'entre eux. Espérons qu'au moins un de ces extraits directement à un tampon, et je peux comprendre comment faire la même chose.



7
votes

Je ne suis pas familier d'unar, après une lecture rapide d'une documentation, je pense que vous supposez que CallBackProc est appelé exactement une fois par fichier. Cependant, je pense que cela peut l'appeler plusieurs fois. Il déballose certaines données alors appelle callbackProc , puis exploitent le morceau de données suivant et appelle à nouveau les appels callbackProc , le processus est itéré jusqu'à ce que toutes les données soient traitées. Vous devez vous rappeler combien d'octets sont réellement écrits sur la mémoire tampon et appendez de nouvelles données à compensation correspondante.


2 commentaires

Il explique définitivement pourquoi les fichiers extraits échoués ont été jumelés mais pas toutes les ordures. Je relisons la documentation et cela ne m'a pas donné d'impression que cela pourrait exécuter le rappel plusieurs fois par fichier. Comment y penses-tu? Avoir un rappel exécuté périodiquement au milieu de l'extraction ne me semble pas très intuitive.


Je suppose que la raison est que les fichiers dans les archives peuvent être suffisamment importants et ne s'intégreraient pas à la mémoire disponible. Déballage de ces fichiers entièrement dans un tampon serait impossible ou au moins inefficace.