osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthDrivers/kml/KMZArchive.cpp

Go to the documentation of this file.
00001 /* -*-c++-*- */
00002 /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
00003  * Copyright 2008-2010 Pelican Mapping
00004  * http://osgearth.org
00005  *
00006  * osgEarth is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU Lesser General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public License
00017  * along with this program.  If not, see <http://www.gnu.org/licenses/>
00018  */
00019 #include "KMZArchive"
00020 #ifdef SUPPORT_KMZ
00021 
00022 #include <osgDB/ReaderWriter>
00023 #include <osgDB/FileNameUtils>
00024 #include <osgDB/ObjectWrapper>
00025 #include <osgEarth/HTTPClient>
00026 #include <osgEarth/Registry>
00027 #include <osgEarth/ThreadingUtils>
00028 
00029 #define LC "[KMZArchive] "
00030 
00031 using namespace osgEarth;
00032 
00033 namespace
00034 {
00035     URI downloadToCache( const URI& uri )
00036     {
00037         // get a handle on the file cache. This is a temporary setup just to get things
00038         // working.
00039         static Threading::Mutex s_fcMutex;
00040 
00041         static URIContext s_cache;
00042         if ( s_cache.empty() )
00043         {
00044             Threading::ScopedMutexLock exclusiveLock(s_fcMutex);
00045             if ( s_cache.empty() )
00046             {
00047                 const char* osgCacheDir = ::getenv("OSG_FILE_CACHE");
00048                 if ( osgCacheDir )
00049                     s_cache = URIContext(std::string(osgCacheDir) + "/");
00050                 else
00051                     s_cache = URIContext("osgearth_kmz_cache/");
00052             }
00053         }
00054 
00055         URI cachedFile( osgDB::getSimpleFileName(uri.full()), s_cache);
00056 
00057         if ( !osgDB::fileExists(cachedFile.full()) )
00058         {
00059             osgDB::makeDirectoryForFile(cachedFile.full());
00060             HTTPClient::download( uri.full(), cachedFile.full() );
00061         }
00062 
00063         if ( osgDB::fileExists(cachedFile.full()) )
00064             return cachedFile;
00065 
00066         return URI();
00067     }
00068 }
00069 
00070 //------------------------------------------------------------------------
00071 
00072 KMZArchive::KMZArchive( const URI& archiveURI ) :
00073 _archiveURI( archiveURI ),
00074 _buf( 0L ),
00075 _bufsize( 1024000 )
00076 {
00077     supportsExtension( "kmz", "KMZ" );
00078 
00079     // download the KMZ to a local cache - cannot open zip files remotely.
00080     URI localURI( archiveURI );
00081     if ( osgDB::containsServerAddress(archiveURI.full()) )
00082     {
00083         localURI = downloadToCache( archiveURI );
00084     }
00085 
00086     _uf = unzOpen( localURI.full().c_str() );
00087     _buf = (void*)new char[_bufsize];
00088 }
00089 
00090 KMZArchive::~KMZArchive()
00091 {
00092     if ( _buf )
00093         delete [] _buf;
00094 }
00095 
00096 void 
00097 KMZArchive::close()
00098 {
00099     _uf = 0;
00100 }
00101 
00103 std::string 
00104 KMZArchive::getArchiveFileName() const
00105 {
00106     return _archiveURI.base();
00107 }
00108 
00110 std::string
00111 KMZArchive::getMasterFileName() const 
00112 {
00113     return "doc.kml";
00114 }
00115 
00117 bool
00118 KMZArchive::fileExists(const std::string& filename) const
00119 {
00120     //todo
00121     return false;
00122 }
00123 
00125 osgDB::FileType
00126 KMZArchive::getFileType(const std::string& filename) const
00127 {
00128     return osgDB::REGULAR_FILE;
00129 }
00130 
00132 bool 
00133 KMZArchive::getFileNames(FileNameList& fileNames) const
00134 {
00135     return false;
00136 }
00137 
00140 osgDB::DirectoryContents 
00141 KMZArchive::getDirectoryContents(const std::string& dirName) const
00142 {
00143     return osgDB::DirectoryContents();
00144 }
00145 
00147 bool 
00148 KMZArchive::readToBuffer( const std::string& fileInZip, std::ostream& iobuf ) const
00149 {
00150     // help from:
00151     // http://bytes.com/topic/c/answers/764381-reading-contents-zip-files
00152 
00153     int err = UNZ_OK;
00154     unz_file_info file_info;
00155     char filename_inzip[2048];
00156     bool got_file_info = false;
00157 
00158     if ( _uf == 0 )
00159     {
00160         OE_WARN << LC << "Archive is not open." << std::endl;
00161         return false;
00162     }
00163 
00164     if ( fileInZip == ".kml" )
00165     {
00166         // special case; first try the master file (doc.kml), then failing that, look
00167         // for the first KML file in the archive.
00168         if ( unzLocateFile( _uf, "doc.kml", 0 ) != 0 )
00169         {
00170             if ( unzGoToFirstFile( _uf ) != UNZ_OK )
00171             {
00172                 OE_WARN << LC << "Archive is empty" << std::endl;
00173                 return false;
00174             }
00175 
00176             while( err == UNZ_OK )
00177             {
00178                 if ( unzGetCurrentFileInfo( _uf, &file_info, filename_inzip, sizeof(filename_inzip), 0L, 0, 0L, 0) )
00179                 {
00180                     OE_WARN << LC << "Error with zipfile " << _archiveURI.base() << std::endl;
00181                     return false;
00182                 }
00183 
00184                 got_file_info = true;
00185                 std::string lc = osgEarth::toLower( std::string(filename_inzip) );
00186                 if ( endsWith( lc, ".kml" ) )
00187                 {
00188                     break;
00189                 }
00190 
00191                 err = unzGoToNextFile( _uf );
00192             }
00193 
00194             if ( err != UNZ_OK )
00195             {
00196                 OE_WARN << LC << "No KML file found in archive" << std::endl;
00197                 return false;
00198             }
00199         }
00200     }
00201 
00202     else if ( unzLocateFile( _uf, fileInZip.c_str(), 0 ) )
00203     {
00204         OE_WARN << LC << "Failed to locate '" << fileInZip << "' in '" << _archiveURI.base() << "'" << std::endl;
00205         return false;
00206     }
00207 
00208     if ( !got_file_info )
00209     {
00210         if ( unzGetCurrentFileInfo( _uf, &file_info, filename_inzip, sizeof(filename_inzip), 0L, 0, 0L, 0) )
00211         {
00212             OE_WARN << LC << "Error with zipfile " << _archiveURI.base() << std::endl;
00213             return false;
00214         }
00215     }
00216 
00217     err = unzOpenCurrentFilePassword( _uf, 0L );
00218     if ( err != UNZ_OK )
00219     {
00220         OE_WARN << LC << "unzOpenCurrentFilePassword failed" << std::endl;
00221         return false;
00222     }
00223 
00224     do
00225     {
00226         err = unzReadCurrentFile( _uf, _buf, _bufsize );
00227         if ( err < 0 )
00228         {
00229             OE_WARN << LC << "Error in unzReadCurrentFile" << std::endl;
00230             break;
00231         }
00232         if ( err > 0 )
00233         {
00234             for( unsigned i=0; i<err; ++i )
00235             {
00236                 iobuf.put( *(((char*)_buf)+i) );
00237             }
00238         }
00239     }
00240     while( err > 0 );
00241 
00242     err = unzCloseCurrentFile( _uf );
00243     if ( err != UNZ_OK )
00244     {
00245         //ignore it...
00246     }
00247 
00248     return true;
00249 }
00250 
00251 osgDB::ReaderWriter::ReadResult
00252 KMZArchive::readImage(const std::string& filename, const osgDB::Options* options) const
00253 {
00254     osgDB::ReaderWriter* rw = osgDB::Registry::instance()->getReaderWriterForExtension(
00255         osgDB::getLowerCaseFileExtension( filename ) );
00256     if ( rw )
00257     {
00258         std::stringstream iobuf;
00259         if ( readToBuffer( filename, iobuf ) )
00260         {
00261             osg::ref_ptr<osgDB::Options> myOptions = Registry::instance()->cloneOrCreateOptions(options);
00262             URIContext(*_archiveURI).add(filename).store( myOptions.get() );
00263             return rw->readImage( iobuf, options );
00264         }
00265         else return ReadResult::ERROR_IN_READING_FILE;
00266     }
00267     else return ReadResult::FILE_NOT_HANDLED;
00268 }
00269 
00270 osgDB::ReaderWriter::ReadResult
00271 KMZArchive::readNode(const std::string& filename, const osgDB::Options* options) const
00272 {
00273     osgDB::ReaderWriter* rw = osgDB::Registry::instance()->getReaderWriterForExtension(
00274         osgDB::getLowerCaseFileExtension( filename ) );
00275     if ( rw )
00276     {
00277         std::stringstream iobuf;
00278         if ( readToBuffer( filename, iobuf ) )
00279         {
00280             osg::ref_ptr<osgDB::Options> myOptions = Registry::instance()->cloneOrCreateOptions(options);
00281             URIContext(*_archiveURI).add(filename).store( myOptions.get() );
00282             return rw->readNode( iobuf, options );
00283         }
00284         else return ReadResult::ERROR_IN_READING_FILE;
00285     }
00286     else return ReadResult::FILE_NOT_HANDLED;
00287 }
00288 
00289 osgDB::ReaderWriter::ReadResult
00290 KMZArchive::readObject(const std::string& filename, const osgDB::Options* options) const
00291 {
00292     osgDB::ReaderWriter* rw = osgDB::Registry::instance()->getReaderWriterForExtension(
00293         osgDB::getLowerCaseFileExtension( filename ) );
00294     if ( rw )
00295     {
00296         std::stringstream iobuf;
00297         if ( readToBuffer( filename, iobuf ) )
00298         {
00299             osg::ref_ptr<osgDB::Options> myOptions = Registry::instance()->cloneOrCreateOptions(options);
00300             URIContext(*_archiveURI).add(filename).store( myOptions.get() );
00301             return rw->readObject( iobuf, myOptions.get() );
00302         }
00303         else return ReadResult::ERROR_IN_READING_FILE;
00304     }
00305     else return ReadResult::FILE_NOT_HANDLED;
00306 }
00307 
00308 #endif // SUPPORT_KMZ
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines