diff --git a/include/osgDB/Archive b/include/osgDB/Archive index bed3bf6ad..4f43168dc 100644 --- a/include/osgDB/Archive +++ b/include/osgDB/Archive @@ -59,7 +59,7 @@ class OSGDB_EXPORT Archive : public ReaderWriter /** return the contents of a directory. * returns an empty array on any error.*/ - virtual DirectoryContents getDirectoryContents(const std::string& dirName) const = 0; + virtual DirectoryContents getDirectoryContents(const std::string& dirName) const; virtual ReadResult readObject(const std::string& /*fileName*/,const Options* =NULL) const = 0; diff --git a/src/osg/Texture2D.cpp b/src/osg/Texture2D.cpp index a08257ffc..09ce2b556 100644 --- a/src/osg/Texture2D.cpp +++ b/src/osg/Texture2D.cpp @@ -306,7 +306,7 @@ void Texture2D::apply(State& state) const glBindTexture( GL_TEXTURE_2D, 0 ); } - // if texture object is now valid and we have to allocate mipmap levels, then + // if texture object is now valid and we have to allocate mipmap levels, then if (textureObject != 0 && _texMipmapGenerationDirtyList[contextID]) { generateMipmap(state); diff --git a/src/osgDB/Archive.cpp b/src/osgDB/Archive.cpp index abd1dfe86..9384c25a1 100644 --- a/src/osgDB/Archive.cpp +++ b/src/osgDB/Archive.cpp @@ -50,3 +50,73 @@ Archive::~Archive() OSG_INFO<<"Archive::~Archive() closed"< searchPath.size()) + { + size_t endSubElement = currentFile.find(searchPath); + + //we match the whole string in the beginning of the path + if(endSubElement == 0) + { + std::string remainingFile = currentFile.substr(searchPath.size() + 1, std::string::npos); + size_t endFileToken = remainingFile.find_first_of('/'); + + if(endFileToken == std::string::npos) + { + dirContents.push_back(remainingFile); + } + } + } + } + + return dirContents; + + +} diff --git a/src/osgPlugins/zip/CMakeLists.txt b/src/osgPlugins/zip/CMakeLists.txt index 403a5423c..93b2fc24d 100644 --- a/src/osgPlugins/zip/CMakeLists.txt +++ b/src/osgPlugins/zip/CMakeLists.txt @@ -1,10 +1,12 @@ SET(TARGET_SRC unzip.cpp + ZipArchive.cpp ReaderWriterZIP.cpp ) SET(TARGET_H unzip.h + ZipArchive.h ) ADD_DEFINITIONS(-DZIP_STD) diff --git a/src/osgPlugins/zip/ReaderWriterZIP.cpp b/src/osgPlugins/zip/ReaderWriterZIP.cpp index 03d451fce..5f276b495 100644 --- a/src/osgPlugins/zip/ReaderWriterZIP.cpp +++ b/src/osgPlugins/zip/ReaderWriterZIP.cpp @@ -3,10 +3,9 @@ #include #include #include -#include #include -#include "unzip.h" +#include "ZipArchive.h" class ReaderWriterZIP : public osgDB::ReaderWriter { @@ -15,251 +14,135 @@ class ReaderWriterZIP : public osgDB::ReaderWriter ReaderWriterZIP() { supportsExtension("zip","Zip archive format"); + osgDB::Registry::instance()->addArchiveExtension("zip"); } virtual const char* className() const { return "ZIP Database Reader/Writer"; } - virtual ReadResult readNode(const std::string& file, const osgDB::Options* options) const - { - ReadResult rresult = ReadResult::FILE_NOT_HANDLED; - //Check to see if option is to load and extract to filesystem - bool bExtractToFileSystem = false; - if (options) - { - std::string optExtractTo = options->getPluginStringData("zipextract"); - if (!(optExtractTo.empty())) - { - if (osgDB::convertToLowerCase(optExtractTo)=="filesystem") - { - bExtractToFileSystem = true; - } - } - } - - if (bExtractToFileSystem) - { - rresult = original_readNode(file,options); - } - else - { - std::string ext = osgDB::getLowerCaseFileExtension(file); - if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED; - - std::string fileName = osgDB::findDataFile( file, options ); - if (fileName.empty()) return ReadResult::FILE_NOT_FOUND; - - OSG_INFO<<"ReaderWriterZIP::readNode( "< local_opt = options ? - static_cast(options->clone(osg::CopyOp::SHALLOW_COPY)) : - new Options; - - // minor issue associated with database path list, as in context of zip file it - // doesn't make sense. Need to set to empty path for other plugins to access - local_opt->getDatabasePathList().push_front(osgDB::getFilePath(file)); - - // Now pass through to memory zip handler - rresult = readNode(tmpStrmBuffer,local_opt.get()); - - // Clean up options - local_opt->getDatabasePathList().pop_front(); - } - } - - return rresult; - } - - virtual ReadResult readNode(std::istream& fin,const osgDB::Options* options) const - { - ReadResult result = ReadResult(ReadResult::FILE_NOT_HANDLED); - - if (fin.fail()) return result; - - fin.seekg(0,std::ios_base::end); - unsigned int ulzipFileLength = fin.tellg(); - fin.seekg(0,std::ios_base::beg); - - // Need to decouple stream content as I can't see any other way to get access to a byte array - // containing the content in the stream. One saving grace here is that we know that the - // stream has already been fully read in, hence no need to concern ourselves with asynchronous - // reads. - char * pMemBuffer = new char [ulzipFileLength]; - if (!pMemBuffer) return result; - - fin.read(pMemBuffer, ulzipFileLength); - if ((unsigned int)fin.gcount() == ulzipFileLength) - { - HZIP hz = OpenZip(pMemBuffer, ulzipFileLength, ""); - if (hz) - { - ZIPENTRY ze; - GetZipItem(hz,-1,&ze); - int numitems=ze.index; - - // Initialise top level group - osg::ref_ptr grp = new osg::Group; - if (grp.valid()) - { - // Now loop through each file in zip - for (int i = 0; i < numitems; i++) - { - GetZipItem(hz,i,&ze); - std::string StreamName = ze.name; - std::stringstream buffer; - - char *ibuf = new char[ze.unc_size]; - if (ibuf) - { - UnzipItem(hz,i, ibuf, ze.unc_size); - buffer.write(ibuf,ze.unc_size); - delete[] ibuf; - // Now ready to read node // - - std::string file_ext = osgDB::getFileExtension(StreamName); - - ReaderWriter* rw = osgDB::Registry::instance()->getReaderWriterForExtension(file_ext); - if (rw) - { - // Setup appropriate options - osg::ref_ptr local_opt = options ? - static_cast(options->clone(osg::CopyOp::SHALLOW_COPY)) : - new Options; - - local_opt->setPluginStringData("STREAM_FILENAME",osgDB::getSimpleFileName(StreamName)); - - ReadResult readResult = rw->readNode(buffer,local_opt.get()); - if (readResult.validNode()) - { - grp->addChild(readResult.takeNode()); - } - } - } - } - if (grp->getNumChildren() > 0) - { - result = grp.get(); - } - } - CloseZip(hz); - } - } - delete [] pMemBuffer; - - return result; - } - - virtual ReadResult original_readNode(const std::string& file, const osgDB::Options* options) const + virtual ReadResult openArchive(const std::string& file,ArchiveStatus status, unsigned int indexBlockSize = 4096, const Options* options = NULL) const { std::string ext = osgDB::getLowerCaseFileExtension(file); if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED; - std::string fileName = osgDB::findDataFile( file, options ); - if (fileName.empty()) return ReadResult::FILE_NOT_FOUND; - - OSG_INFO<<"ReaderWriterZIP::readNode( "< grp = new osg::Group; - - osg::ref_ptr local_options = options ? static_cast(options->clone(osg::CopyOp::SHALLOW_COPY)) : new osgDB::ReaderWriter::Options; - local_options->getDatabasePathList().push_front(dirname); - - // deactivate the automatic generation of images to geode's. - bool prevCreateNodeFromImage = osgDB::Registry::instance()->getCreateNodeFromImage(); - osgDB::Registry::instance()->setCreateNodeFromImage(false); - - osgDB::DirectoryContents contents = osgDB::getDirectoryContents(dirname); - for(osgDB::DirectoryContents::iterator itr = contents.begin(); - itr != contents.end(); - ++itr) + std::string fileName = osgDB::findDataFile(file, options); + if (fileName.empty()) { - std::string file_ext = osgDB::getFileExtension(*itr); - if (!acceptsExtension(file_ext) && - *itr!=std::string(".") && - *itr!=std::string("..")) - { - osg::Node *node = osgDB::readNodeFile( *itr, local_options.get() ); - grp->addChild( node ); - } + //we do not support writing so the file must exist + return ReadResult::FILE_NOT_FOUND; } - osgDB::Registry::instance()->setCreateNodeFromImage(prevCreateNodeFromImage); + // copy the incoming options if possible so that plugin options can be applied to files + // inside the archive + osg::ref_ptr local_options = options? + options->cloneOptions() : + new osgDB::ReaderWriter::Options; - #if defined(WIN32) && !defined(__CYGWIN__) - // note, is this the right command for windows? - // is there any way of overiding the Y/N option? RO. - sprintf( command, "erase /S /Q \"%s\"", dirname ); - int result = system( command ); - #else - - sprintf( command, "rm -rf %s", dirname ); - int result = system( command ); - #endif - if (result!=0) return ReadResult::ERROR_IN_READING_FILE; - - if( grp->getNumChildren() == 0 ) + osg::ref_ptr archive = new ZipArchive; + if (!archive->open(fileName, osgDB::ReaderWriter::READ, local_options.get())) { - return ReadResult::FILE_NOT_HANDLED; + return ReadResult(ReadResult::FILE_NOT_HANDLED); } - return grp.get(); + return archive.get(); + } + + /** open an archive for reading.*/ + virtual ReadResult openArchive(std::istream& fin, const Options* options) const + { + osg::ref_ptr archive = new ZipArchive; + if (!archive->open(fin, options)) + { + return ReadResult(ReadResult::FILE_NOT_HANDLED); + } + + return archive.get(); + } + + + virtual osgDB::ReaderWriter::ReadResult readNode(const std::string& file, const osgDB::ReaderWriter::Options* options) const + { + osgDB::ReaderWriter::ReadResult result = openArchive(file, osgDB::Archive::READ); + + if (!result.validArchive()) return result; + + // copy the incoming options if possible so that plugin options can be applied to files + // inside the archive + osg::ref_ptr local_options = options? + options->cloneOptions() : + new osgDB::ReaderWriter::Options; + + local_options->setDatabasePath(file); + + //todo- what should we read here? + osgDB::ReaderWriter::ReadResult result_2 = result.getArchive()->readNode(result.getArchive()->getMasterFileName(),local_options.get()); + + if (!options || (options->getObjectCacheHint() & osgDB::ReaderWriter::Options::CACHE_ARCHIVES)) + { + // register the archive so that it is cached for future use. + osgDB::Registry::instance()->addToArchiveCache(file, result.getArchive()); + } + + return result_2; + + } + + virtual ReadResult readNode(std::istream& fin,const osgDB::ReaderWriter::Options* options) const + { + + osgDB::ReaderWriter::ReadResult result = openArchive(fin, options); + + if (!result.validArchive()) return result; + + // copy the incoming options if possible so that plugin options can be applied to files + // inside the archive + osg::ref_ptr local_options = options? + options->cloneOptions() : + new osgDB::ReaderWriter::Options; + + //todo- what should the database path be? + //local_options->setDatabasePath(file); + + + //todo- what should we read here? + osgDB::ReaderWriter::ReadResult result_2 = result.getArchive()->readNode(result.getArchive()->getMasterFileName(),local_options.get()); + + //todo- what to do to cache the archive here? + //if (!options || (options->getObjectCacheHint() & osgDB::ReaderWriter::Options::CACHE_ARCHIVES)) + //{ + // // register the archive so that it is cached for future use. + // osgDB::Registry::instance()->addToArchiveCache(file, result.getArchive()); + //} + + return result_2; + } + + virtual ReadResult readImage(const std::string& file,const Options* options) const + { + ReadResult result = openArchive(file,osgDB::Archive::READ); + + if (!result.validArchive()) return result; + + + // copy the incoming options if possible so that plugin options can be applied to files + // inside the archive + osg::ref_ptr local_options = options? + options->cloneOptions() : + new osgDB::ReaderWriter::Options; + + local_options->setDatabasePath(file); + + ReadResult result_2 = result.getArchive()->readImage(result.getArchive()->getMasterFileName(),local_options.get()); + + + if (!options || (options->getObjectCacheHint() & osgDB::ReaderWriter::Options::CACHE_ARCHIVES)) + { + // register the archive so that it is cached for future use. + osgDB::Registry::instance()->addToArchiveCache(file, result.getArchive()); + } + + return result_2; } }; diff --git a/src/osgPlugins/zip/unzip.cpp b/src/osgPlugins/zip/unzip.cpp index c6e5cc7d2..dca61bf5b 100644 --- a/src/osgPlugins/zip/unzip.cpp +++ b/src/osgPlugins/zip/unzip.cpp @@ -4203,10 +4203,25 @@ ZRESULT TUnzip::Unzip(int index,void *dst,unsigned int len,DWORD flags) } bool reached_eof; int res = unzReadCurrentFile(uf,dst,len,&reached_eof); - if (res<=0) {unzCloseCurrentFile(uf); currentfile=-1;} - if (reached_eof) return ZR_OK; - if (res>0) return ZR_MORE; - if (res==UNZ_PASSWORD) return ZR_PASSWORD; + if (res<=0) + { + unzCloseCurrentFile(uf); currentfile=-1; + } + if (reached_eof) + { + unzCloseCurrentFile(uf); + currentfile=-1; + return ZR_OK; + } + if (res>0) + { + return ZR_MORE; + } + if (res==UNZ_PASSWORD) + { + return ZR_PASSWORD; + } + return ZR_FLATE; } // otherwise we're writing to a handle or a file