Home | History | Annotate | Download | only in dae
      1 #ifndef NO_ZAE
      2 #include <fstream>
      3 #include <dae.h>
      4 #include <dae/daeErrorHandler.h>
      5 #include <dae/daeZAEUncompressHandler.h>
      6 
      7 //-----------------------------------------------------------------
      8 const std::string daeZAEUncompressHandler::MANIFEST_FILE_NAME("manifest.xml");
      9 const std::string daeZAEUncompressHandler::MANIFEST_FILE_ROOT_ELEMENT_NAME("dae_root");
     10 const int daeZAEUncompressHandler::CASE_INSENSITIVE = 2;
     11 const int daeZAEUncompressHandler::BUFFER_SIZE = 1024;
     12 const std::string daeZAEUncompressHandler::EMPTY_STRING = "";
     13 
     14 //-----------------------------------------------------------------
     15 daeZAEUncompressHandler::daeZAEUncompressHandler( const daeURI& zaeFile )
     16   : mZipFile(NULL)
     17   , mZipFileURI(zaeFile)
     18   , mValidZipFile(false)
     19   , mRootFilePath("")
     20 {
     21     std::string zipFilePath = cdom::uriToNativePath(zaeFile.getURI());
     22     mZipFile = unzOpen(zipFilePath.c_str());
     23 
     24     mValidZipFile = mZipFile != NULL;
     25 
     26     mTmpDir = cdom::getSafeTmpDir() + cdom::getRandomFileName() +
     27         cdom::getFileSeparator() + mZipFileURI.pathFile() + cdom::getFileSeparator();
     28 }
     29 
     30 //-----------------------------------------------------------------
     31 daeZAEUncompressHandler::~daeZAEUncompressHandler()
     32 {
     33     if (mZipFile != NULL)
     34         unzClose(mZipFile);
     35 }
     36 
     37 //-----------------------------------------------------------------
     38 const std::string& daeZAEUncompressHandler::obtainRootFilePath()
     39 {
     40     if (!isZipFile())
     41         return EMPTY_STRING;
     42 
     43     if (boost::filesystem::create_directories(mTmpDir))
     44     {
     45         if (extractArchive(mZipFile, mTmpDir))
     46         {
     47             if (retrieveRootURIFromManifest(mTmpDir))
     48             {
     49                 return mRootFilePath;
     50             }
     51             else
     52             {
     53                 // TODO find root file without manifest
     54             }
     55         }
     56         else
     57         {
     58             daeErrorHandler::get()->handleError("Error extracting archive in daeZAEUncompressHandler::obtainRootFilePath\n");
     59         }
     60     }
     61     else
     62     {
     63         daeErrorHandler::get()->handleError("Error creating tmp dir in daeZAEUncompressHandler::obtainRootFilePath\n");
     64     }
     65 
     66     boost::filesystem::remove_all(this->getTmpDir());
     67     return EMPTY_STRING;
     68 }
     69 
     70 //-----------------------------------------------------------------
     71 bool daeZAEUncompressHandler::retrieveRootURIFromManifest(const std::string& tmpDir)
     72 {
     73     // extract via libxml.
     74     bool error = false;
     75     xmlTextReaderPtr xmlReader = xmlReaderForFile(
     76         (tmpDir + MANIFEST_FILE_NAME).c_str(),
     77         NULL,
     78         0
     79         );
     80 
     81     if (xmlReader)
     82     {
     83         if (findManifestRootElement(xmlReader))
     84         {
     85             if (xmlTextReaderRead(xmlReader))
     86             {
     87                 if (xmlTextReaderNodeType(xmlReader) == XML_READER_TYPE_TEXT) {
     88                     const xmlChar* xmlText = xmlTextReaderConstValue(xmlReader);
     89 
     90                     // copy xmlText.
     91                     std::string rootFilePath((daeString)xmlText);
     92 
     93                     // destroy xmlText.
     94                     xmlTextReaderRead(xmlReader);
     95 
     96                     cdom::trimWhitespaces(rootFilePath);
     97                     mRootFilePath = cdom::nativePathToUri(tmpDir + rootFilePath);
     98                 }
     99                 else
    100                 {
    101                     error = true;
    102                 }
    103             }
    104             else
    105             {
    106                 error = true;
    107             }
    108         }
    109         else
    110         {
    111             error = true;
    112         }
    113     }
    114     else
    115     {
    116         error = true;
    117     }
    118 
    119     if (xmlReader)
    120         xmlFreeTextReader(xmlReader);
    121     if (error)
    122     {
    123         daeErrorHandler::get()->handleError("Error parsing manifest.xml in daeZAEUncompressHandler::retrieveRootURIFromManifest\n");
    124         return false;
    125     }
    126 
    127     return true;
    128 }
    129 
    130 //-----------------------------------------------------------------
    131 bool daeZAEUncompressHandler::findManifestRootElement( xmlTextReaderPtr xmlReader )
    132 {
    133     while(xmlTextReaderNodeType(xmlReader) != XML_READER_TYPE_ELEMENT)
    134     {
    135         if (xmlTextReaderRead(xmlReader) != 1) {
    136             return false;
    137         }
    138     }
    139 
    140     daeString elementName = (daeString)xmlTextReaderConstName(xmlReader);
    141     if (strcmp(elementName, MANIFEST_FILE_ROOT_ELEMENT_NAME.c_str()) == 0)
    142     {
    143         return true;
    144     }
    145     return findManifestRootElement(xmlReader);
    146 }
    147 
    148 //-----------------------------------------------------------------
    149 bool daeZAEUncompressHandler::extractArchive( unzFile zipFile, const std::string& destDir )
    150 {
    151     bool error = false;
    152     unz_global_info globalZipInfo;
    153 
    154     if (unzGetGlobalInfo (zipFile, &globalZipInfo) == UNZ_OK)
    155     {
    156         for (unsigned int i=0; i<globalZipInfo.number_entry; ++i)
    157         {
    158             if (!extractFile(zipFile, destDir))
    159             {
    160                 error = true;
    161                 break;
    162             }
    163 
    164             if ((i+1)<globalZipInfo.number_entry)
    165             {
    166                 if (unzGoToNextFile(zipFile) != UNZ_OK)
    167                 {
    168                     daeErrorHandler::get()->handleError("Error moving to next file in zip archive in daeZAEUncompressHandler::extractArchive\n");
    169                     error = true;
    170                     break;
    171                 }
    172             }
    173         }
    174     }
    175     else
    176     {
    177         daeErrorHandler::get()->handleError("Error getting info for zip archive in daeZAEUncompressHandler::extractArchive\n");
    178         error = true;
    179     }
    180     return !error;
    181 }
    182 
    183 //-----------------------------------------------------------------
    184 bool daeZAEUncompressHandler::extractFile( unzFile zipFile,  const std::string& destDir )
    185 {
    186     bool error = false;
    187 
    188     unz_file_info fileInfo;
    189     char currentFileName[256]; // ARGH !!!
    190     int fileInfoResult = unzGetCurrentFileInfo(zipFile, &fileInfo, currentFileName, sizeof(currentFileName), 0, 0, 0, 0);
    191     if (fileInfoResult == UNZ_OK)
    192     {
    193         if ( currentFileName[ strlen(currentFileName)-1 ] == '/')
    194         {
    195             if (!boost::filesystem::create_directories(destDir + currentFileName))
    196             {
    197                 daeErrorHandler::get()->handleError("Error creating dir from zip archive in daeZAEUncompressHandler::extractFile\n");
    198                 error = true;
    199             }
    200         }
    201         else
    202         {
    203             if (unzOpenCurrentFile(zipFile) == UNZ_OK)
    204             {
    205 
    206                 char* buffer = 0;
    207                 int readBytes = 1;
    208                 buffer = new char[ BUFFER_SIZE ];
    209                 std::string currentOutFilePath(destDir + std::string(currentFileName));
    210                 std::ofstream outFile(currentOutFilePath.c_str(), std::ios::binary);
    211 
    212                 while (readBytes > 0)
    213                 {
    214                     readBytes = unzReadCurrentFile(zipFile, buffer, BUFFER_SIZE);
    215                     outFile.write(buffer, readBytes);
    216                 }
    217                 delete[] buffer;
    218                 outFile.close();
    219 
    220                 if (readBytes >= 0)
    221                 {
    222                     if (unzCloseCurrentFile(zipFile) == UNZ_CRCERROR)
    223                     {
    224                         daeErrorHandler::get()->handleError("CRC error while opening file in zip archive in daeZAEUncompressHandler::extractFile\n");
    225                         error = true;
    226                     }
    227                     else
    228                     {
    229                         if (!checkAndExtractInternalArchive(currentOutFilePath))
    230                         {
    231                             error = true;
    232                         }
    233                     }
    234                 }
    235                 else
    236                 {
    237                     daeErrorHandler::get()->handleError("Error reading file in zip archive in daeZAEUncompressHandler::extractFile\n");
    238                     error = true;
    239                 }
    240 
    241             }
    242             else
    243             {
    244                 daeErrorHandler::get()->handleError("Error opening file in zip archive in daeZAEUncompressHandler::extractFile\n");
    245                 error = true;
    246             }
    247         }
    248     }
    249     else
    250     {
    251         daeErrorHandler::get()->handleError("Error getting info for file in zip archive in daeZAEUncompressHandler::extractFile\n");
    252         error = true;
    253     }
    254 
    255     return !error;
    256 }
    257 
    258 //-----------------------------------------------------------------
    259 bool daeZAEUncompressHandler::checkAndExtractInternalArchive( const std::string& filePath )
    260 {
    261     unzFile zipFile = unzOpen(filePath.c_str());
    262     if (zipFile == NULL)
    263     {
    264         // TODO check for other compression formats.
    265         return true;
    266     }
    267 
    268     bool error = false;
    269 
    270     boost::filesystem::path archivePath(filePath);
    271     std::string dir = archivePath.branch_path().string();
    272 
    273     const std::string& randomSegment = cdom::getRandomFileName();
    274     std::string tmpDir = dir + cdom::getFileSeparator() + randomSegment + cdom::getFileSeparator();
    275     if (boost::filesystem::create_directory(tmpDir))
    276     {
    277         if (!extractArchive(zipFile, tmpDir))
    278         {
    279             daeErrorHandler::get()->handleError("Could not extract internal zip archive in daeZAEUncompressHandler::checkAndExtractInternalArchive\n");
    280             error = true;
    281         }
    282     }
    283     else
    284     {
    285         daeErrorHandler::get()->handleError("Could not create temporary directory for extracting internal zip archive in daeZAEUncompressHandler::checkAndExtractInternalArchive\n");
    286         error = true;
    287     }
    288 
    289     unzClose(zipFile);
    290 
    291     if (!error)
    292     {
    293         if (boost::filesystem::remove(archivePath))
    294         {
    295             boost::filesystem::rename(tmpDir, archivePath);
    296         }
    297         else
    298         {
    299             daeErrorHandler::get()->handleError("Could not remove internal zip archive in daeZAEUncompressHandler::checkAndExtractInternalArchive\n");
    300             error = true;
    301         }
    302     }
    303 
    304     return !error;
    305 }
    306 
    307 #endif //NO_ZAE
    308