From 38b02a26a9387384d731405bc14981fb067e1221 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Thu, 9 Apr 2009 14:00:16 +0000 Subject: [PATCH] From Glenn Waldron, "Here is a first cut at the mime-type support we discussed a little while ago (http://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg23098.html) Background: when you access a file over HTTP, you cannot rely on a file extension being present; instead the file's mime-type is conveyed in the HTTP Content-Type response header. This facility adds a mime-type-to-extension map to the registry to handle this. There are two new osgDB::Registry functions which are pretty self-explanatory: void addMimeTypeExtensionMapping( mime-type, extension ) ReaderWriter* getReaderWriterForMimeType( mime-type ) I also added the file osgDB/MimeTypes.cpp which houses a hard-coded list of built-in types. I took the list from here (http://www.webmaster-toolkit.com/mime-types.shtml) and then pared it down to include mostly image and video types, editing them to map to existing plugins where possible. In addition, I updated the CURL plugin to a) install a set of built-in mime-type mappings, and b) use them to look up an extension in the event that the target filename does not have an extension. Here is a test case. This URL pulls down a JPEG (without a file extension): osgviewer --image "http://us.maps3.yimg.com/aerial.maps.yimg.com/ximg?v=1.8&s=256&t=a&r=1&x=0&y=0&z=2" " --- include/osgDB/Registry | 14 +++ src/osgDB/CMakeLists.txt | 1 + src/osgDB/MimeTypes.cpp | 127 +++++++++++++++++++++++ src/osgDB/Registry.cpp | 27 ++++- src/osgPlugins/curl/ReaderWriterCURL.cpp | 46 ++++++-- src/osgPlugins/curl/ReaderWriterCURL.h | 5 + 6 files changed, 213 insertions(+), 7 deletions(-) create mode 100644 src/osgDB/MimeTypes.cpp diff --git a/include/osgDB/Registry b/include/osgDB/Registry index d9e7c79ca..73e9f25bc 100644 --- a/include/osgDB/Registry +++ b/include/osgDB/Registry @@ -94,6 +94,12 @@ class OSGDB_EXPORT Registry : public osg::Referenced * method. Lines can be commented out with an initial '#' character.*/ bool readPluginAliasConfigurationFile( const std::string& file ); + /** Registers a mapping of a mime-type to an extension. A process fetching data + * over HTTP can use this facility to determine the proper ReaderWriter to use + * when there is no filename extension to rely upon. + */ + void addMimeTypeExtensionMapping(const std::string fromMimeType, const std::string toExt); + void addDotOsgWrapper(DotOsgWrapper* wrapper); void removeDotOsgWrapper(DotOsgWrapper* wrapper); @@ -129,6 +135,10 @@ class OSGDB_EXPORT Registry : public osg::Referenced /** get a reader writer which handles specified extension.*/ ReaderWriter* getReaderWriterForExtension(const std::string& ext); + + /** gets a reader/writer that handles the extension mapped to by one of + * the registered mime-types. */ + ReaderWriter* getReaderWriterForMimeType(const std::string& mimeType); /** get list of all registered ReaderWriters.*/ ReaderWriterList& getReaderWriterList() { return _rwList; } @@ -492,6 +502,7 @@ class OSGDB_EXPORT Registry : public osg::Referenced typedef std::map< std::string, osg::ref_ptr > DotOsgWrapperMap; typedef std::vector< osg::ref_ptr > DynamicLibraryList; typedef std::map< std::string, std::string> ExtensionAliasMap; + typedef std::map< std::string, std::string> MimeTypeExtensionMap; typedef std::vector< std::string> ArchiveExtensionList; typedef std::pair, double > ObjectTimeStampPair; @@ -592,6 +603,9 @@ class OSGDB_EXPORT Registry : public osg::Referenced // map to alias to extensions to plugins. ExtensionAliasMap _extAliasMap; + // maps mime-types to extensions. + MimeTypeExtensionMap _mimeTypeExtMap; + // Utility: Removes whitespace from both ends of a string. static std::string trim( const std::string& str ); diff --git a/src/osgDB/CMakeLists.txt b/src/osgDB/CMakeLists.txt index 666490ceb..52ba60091 100644 --- a/src/osgDB/CMakeLists.txt +++ b/src/osgDB/CMakeLists.txt @@ -68,6 +68,7 @@ ADD_LIBRARY(${LIB_NAME} ImageOptions.cpp ImagePager.cpp Input.cpp + MimeTypes.cpp Output.cpp PluginQuery.cpp ReaderWriter.cpp diff --git a/src/osgDB/MimeTypes.cpp b/src/osgDB/MimeTypes.cpp new file mode 100644 index 000000000..6af022926 --- /dev/null +++ b/src/osgDB/MimeTypes.cpp @@ -0,0 +1,127 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ +const char* builtinMimeTypeExtMappings[] = +{ + "application/dxf","dxf", + "application/gnutar","tgz", + "application/pdf","pdf", + "application/plain","text", + "application/postscript","ps", + "application/x-bzip","bz", + "application/x-bzip2","bz2", + "application/x-compressed","zip", + "application/x-gzip","gz", + "application/x-inventor","iv", + "application/x-javascript","js", + "application/xml","xml", + "application/x-tar","tar", + "application/x-vrml","wrl", + "application/x-world","wrl", + "application/x-zip-compressed","zip", + "application/zip","zip", + "drawing/x-dwf(old)","dwf", + "image/bmp","bmp", + "image/cmu-raster","ras", + "image/fif","fif", + "image/florian","flo", + "image/g3fax","g3", + "image/gif","gif", + "image/ief","ief", + "image/jpeg","jpg", + "image/jutvision","jut", + "image/naplps","nap", + "image/naplps","naplps", + "image/pict","pic", + "image/pjpeg","jpg", + "image/png","png", + "image/tiff","tif", + "image/vasa","mcf", + "image/vnd.dwg","dxf", + "image/vnd.fpx","fpx", + "image/vnd.net-fpx","fpx", + "image/vnd.rn-realflash","rf", + "image/vnd.rn-realpix","rp", + "image/vnd.wap.wbmp","wbmp", + "image/vnd.xiff","xif", + "image/xbm","xbm", + "image/x-cmu-raster","ras", + "image/x-dwg","dxf", + "image/x-icon","ico", + "image/x-jg","art", + "image/x-jps","jps", + "image/x-niff","nif", + "image/x-pcx","pcx", + "image/x-pict","pct", + "image/xpm","xpm", + "image/x-portable-anymap","pnm", + "image/x-portable-bitmap","pbm", + "image/x-portable-graymap","pgm", + "image/x-portable-greymap","pgm", + "image/x-portable-pixmap","ppm", + "image/x-quicktime","qif", + "image/x-rgb","rgb", + "image/x-tiff","tif", + "image/x-windows-bmp","bmp", + "image/x-xbitmap","xbm", + "image/x-xbm","xbm", + "image/x-xpixmap","xpm", + "image/x-xwd","xwd", + "image/x-xwindowdump","xwd", + "i-world/i-vrml","ivr", + "model/iges","igs", + "model/vnd.dwf","dwf", + "model/vrml","wrl", + "model/x-pov","pov", + "multipart/x-gzip","gzip", + "multipart/x-ustar","ustar", + "multipart/x-zip","zip", + "video/animaflex","afl", + "video/avi","avi", + "video/avs-video","avs", + "video/dl","dl", + "video/fli","fli", + "video/gl","gl", + "video/mpeg","mpg", + "video/msvideo","avi", + "video/quicktime","qt", + "video/vdo","vdo", + "video/vivo","viv", + "video/vnd.rn-realvideo","rv", + "video/vnd.vivo","viv", + "video/vosaic","vos", + "video/x-amt-demorun","xdr", + "video/x-amt-showrun","xsr", + "video/x-atomic3d-feature","fmf", + "video/x-dl","dl", + "video/x-dv","dv", + "video/x-fli","fli", + "video/x-gl","gl", + "video/x-isvideo","isu", + "video/x-motion-jpeg","mjpg", + "video/x-mpeg","mp3", + "video/x-mpeq2a","mp2", + "video/x-ms-asf","asf", + "video/x-ms-asf-plugin","asx", + "video/x-msvideo","avi", + "video/x-qtc","qtc", + "video/x-scm","scm", + "video/x-sgi-movie","movie", + "windows/metafile","wmf", + "xgl/drawing","xgz", + "xgl/movie","xmz", + "x-world/x-3dmf","3dm", + "x-world/x-svr","svr", + "x-world/x-vrml","wrl", + "x-world/x-vrt","vrt", + "" // end of list +}; diff --git a/src/osgDB/Registry.cpp b/src/osgDB/Registry.cpp index 4d4856a2c..a8348a12a 100644 --- a/src/osgDB/Registry.cpp +++ b/src/osgDB/Registry.cpp @@ -63,6 +63,10 @@ static osg::ApplicationUsageProxy Registry_e1(osg::ApplicationUsage::ENVIRONMENT static osg::ApplicationUsageProxy Registry_e2(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_BUILD_KDTREES on/off","Enable/disable the automatic building of KdTrees for each loaded Geometry."); +// from MimeTypes.cpp +extern const char* builtinMimeTypeExtMappings[]; + + class Registry::AvailableReaderWriterIterator { public: @@ -331,9 +335,17 @@ Registry::Registry() addFileExtensionAlias("pgm", "pnm"); addFileExtensionAlias("ppm", "pnm"); + // add built-in mime-type extension mappings + for( int i=0; ; i+=2 ) + { + std::string mimeType = builtinMimeTypeExtMappings[i]; + if ( mimeType.length() == 0 ) + break; + addMimeTypeExtensionMapping( mimeType, builtinMimeTypeExtMappings[i+1] ); + } + // register http-protocol, so the curl can handle it, if necessary registerProtocol("http"); - } @@ -587,6 +599,11 @@ void Registry::addFileExtensionAlias(const std::string mapExt, const std::string _extAliasMap[mapExt] = toExt; } +void Registry::addMimeTypeExtensionMapping(const std::string fromMimeType, const std::string toExt) +{ + _mimeTypeExtMap[fromMimeType] = toExt; +} + bool Registry::readPluginAliasConfigurationFile( const std::string& file ) { std::string fileName = osgDB::findDataFile( file ); @@ -825,6 +842,14 @@ ReaderWriter* Registry::getReaderWriterForExtension(const std::string& ext) } +ReaderWriter* Registry::getReaderWriterForMimeType(const std::string& mimeType) +{ + MimeTypeExtensionMap::const_iterator i = _mimeTypeExtMap.find( mimeType ); + return i != _mimeTypeExtMap.end()? + getReaderWriterForExtension( i->second ) : + NULL; +} + struct concrete_wrapper: basic_type_wrapper { virtual ~concrete_wrapper() {} diff --git a/src/osgPlugins/curl/ReaderWriterCURL.cpp b/src/osgPlugins/curl/ReaderWriterCURL.cpp index 136863144..99c9fd43e 100644 --- a/src/osgPlugins/curl/ReaderWriterCURL.cpp +++ b/src/osgPlugins/curl/ReaderWriterCURL.cpp @@ -57,6 +57,11 @@ void EasyCurl::StreamObject::write(const char* ptr, size_t realsize) } } } + +std::string EasyCurl::getResultMimeType(const StreamObject& sp) const +{ + return sp._resultMimeType; +} size_t EasyCurl::StreamMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data) { @@ -192,6 +197,15 @@ osgDB::ReaderWriter::ReadResult EasyCurl::read(const std::string& proxyAddress, return rr; } + // Store the mime-type, if any. (Note: CURL manages the buffer returned by + // this call.) + char* ctbuf = NULL; + if ( curl_easy_getinfo(_curl, CURLINFO_CONTENT_TYPE, &ctbuf) == 0 && ctbuf ) + { + sp._resultMimeType = ctbuf; + } + + return osgDB::ReaderWriter::ReadResult::FILE_LOADED; } @@ -213,7 +227,7 @@ ReaderWriterCURL::ReaderWriterCURL() supportsExtension("curl","Psuedo file extension, used to select curl plugin."); supportsExtension("*","Passes all read files to other plugins to handle actual model loading."); supportsOption("OSG_CURL_PROXY","Specify the http proxy."); - supportsOption("OSG_CURL_PROXYPORT","Specify the http proxy oirt."); + supportsOption("OSG_CURL_PROXYPORT","Specify the http proxy port."); } ReaderWriterCURL::~ReaderWriterCURL() @@ -324,14 +338,16 @@ osgDB::ReaderWriter::ReadResult ReaderWriterCURL::readFile(ObjectType objectType } + // Try to find a reader by file extension. If this fails, we will fetch the file + // anyway and try to get a reader via mime-type. osgDB::ReaderWriter *reader = osgDB::Registry::instance()->getReaderWriterForExtension( ext ); - if (!reader) - { - osg::notify(osg::NOTICE)<<"Error: No ReaderWriter for file "< 0 ) + { + reader = osgDB::Registry::instance()->getReaderWriterForMimeType(mimeType); + } + } + + // If there is still no reader, fail. + if ( !reader ) + { + osg::notify(osg::NOTICE)<<"Error: No ReaderWriter for file "< local_opt = options ? static_cast(options->clone(osg::CopyOp::SHALLOW_COPY)) : diff --git a/src/osgPlugins/curl/ReaderWriterCURL.h b/src/osgPlugins/curl/ReaderWriterCURL.h index 271b7d42b..93d499c12 100644 --- a/src/osgPlugins/curl/ReaderWriterCURL.h +++ b/src/osgPlugins/curl/ReaderWriterCURL.h @@ -44,6 +44,7 @@ class EasyCurl : public osg::Referenced bool _foutOpened; std::string _cacheFileName; std::ofstream _fout; + std::string _resultMimeType; }; static size_t StreamMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data); @@ -52,6 +53,10 @@ class EasyCurl : public osg::Referenced osgDB::ReaderWriter::ReadResult read(const std::string& proxyAddress, const std::string& fileName, StreamObject& sp, const osgDB::ReaderWriter::Options *options); + /** Returns the mime type of the data retrieved with the provided stream object on a + * previous call to EasyCurl::read(). */ + std::string getResultMimeType(const StreamObject& sp) const; + protected: virtual ~EasyCurl();