root/OpenSceneGraph/trunk/src/osgPlugins/curl/ReaderWriterCURL.cpp @ 13041

Revision 13041, 23.7 kB (checked in by robert, 3 years ago)

Ran script to remove trailing spaces and tabs

  • Property svn:eol-style set to native
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2008 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13
14#include <osgDB/FileUtils>
15#include <osgDB/ReadFile>
16#include <osgDB/WriteFile>
17#include <osgDB/Registry>
18
19#include <iostream>
20#include <sstream>
21#include <fstream>
22
23#include <string.h>
24
25#include <curl/curl.h>
26
27#if LIBCURL_VERSION_NUM < 0x071503
28    // types.h has been removed in 7.21.7 so have to protect with version guard
29    // it may be possible to remove it completely but can't yet work out when
30    // types.h was deprecated so will assume it's still needed in older libcurl versions
31    // that OSG users are using.
32    #include <curl/types.h>
33#endif
34
35#include "ReaderWriterCURL.h"
36
37using namespace osg_curl;
38
39
40//
41//  StreamObject
42//
43EasyCurl::StreamObject::StreamObject(std::ostream* outputStream, std::istream* inputStream, const std::string& cacheFileName):
44    _outputStream(outputStream),
45    _inputStream(inputStream),
46    _cacheFileName(cacheFileName)
47{
48    _foutOpened = false;
49}
50
51void EasyCurl::StreamObject::write(const char* ptr, size_t realsize)
52{
53    if (_outputStream) _outputStream->write(ptr, realsize);
54
55    if (!_cacheFileName.empty())
56    {
57        if (!_foutOpened)
58        {
59            OSG_INFO<<"Writing to cache: "<<_cacheFileName<<std::endl;
60            _fout.open(_cacheFileName.c_str(), std::ios::out | std::ios::binary);
61            _foutOpened = true;
62        }
63
64        if (_fout)
65        {
66            _fout.write(ptr, realsize);
67        }
68    }
69}
70
71size_t EasyCurl::StreamObject::read(char* ptr, size_t maxsize)
72{
73    if (!_inputStream) return 0;
74    _inputStream->read(ptr, maxsize);
75    size_t realsize = _inputStream->gcount();
76    return realsize;
77}
78
79std::string EasyCurl::getResultMimeType(const StreamObject& sp) const
80{
81    return sp._resultMimeType;
82}
83
84std::string EasyCurl::getMimeTypeForExtension(const std::string& ext) const
85{
86    const osgDB::Registry::MimeTypeExtensionMap& mimeMap = osgDB::Registry::instance()->getMimeTypeExtensionMap();
87    osgDB::Registry::MimeTypeExtensionMap::const_iterator i;
88    for (i = mimeMap.begin(); i != mimeMap.end(); ++i)
89    {
90        if (ext == i->second) return i->first;
91    }
92    return "application/octet-stream"; // unknown mime type
93}
94
95std::string EasyCurl::getFileNameFromURL(const std::string& url)
96{
97    // If the URL has query parameter "filename", return its value,
98    // otherwise just return url assuming it has a filename at the end.
99    // Typically, uploading will require cooperation with a server side
100    // script that requires parameters such as filename and/or session
101    // and/or authentication information, so in general the filename
102    // can not be assumed to be at the tail of the URL.
103    std::string::size_type pos = url.find('?');
104    if (pos == std::string::npos) return url;
105    std::string params = url.substr(pos + 1);
106    const char* filenameKey = "filename=";
107    pos = params.find(filenameKey);
108    if (pos == std::string::npos)
109    {
110        // No filename param, so just chop off parameters on the url.
111        return url.substr(0, url.find('?'));
112    }
113    std::string fileName = params.substr(pos + strlen(filenameKey));
114    pos = fileName.find("&");
115    if (pos != std::string::npos)
116    {
117        // Chop off next url parameter
118        fileName = fileName.substr(0, pos);
119    }
120    return fileName;
121}
122
123size_t EasyCurl::StreamMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)
124{
125    size_t realsize = size * nmemb;
126    StreamObject* sp = (StreamObject*)data;
127
128    sp->write((const char*)ptr, realsize);
129
130    return realsize;
131}
132
133
134///////////////////////////////////////////////////////////////////////////////////////////////////
135//
136//  EasyCurl
137//
138EasyCurl::EasyCurl()
139{
140    OSG_INFO<<"EasyCurl::EasyCurl()"<<std::endl;
141
142    _previousHttpAuthentication = 0;
143    _connectTimeout = 0; // no timeout by default.
144    _timeout = 0;
145
146    _curl = curl_easy_init();
147
148    curl_easy_setopt(_curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
149    curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, StreamMemoryCallback);
150    curl_easy_setopt(_curl, CURLOPT_FOLLOWLOCATION, 1L);
151}
152
153EasyCurl::~EasyCurl()
154{
155    OSG_INFO<<"EasyCurl::~EasyCurl()"<<std::endl;
156
157    if (_curl) curl_easy_cleanup(_curl);
158
159    _curl = 0;
160}
161
162osgDB::ReaderWriter::ReadResult EasyCurl::read(const std::string& proxyAddress, const std::string& fileName, StreamObject& sp, const osgDB::ReaderWriter::Options *options)
163{
164    setOptions(proxyAddress, fileName, sp, options);
165
166    CURLcode responseCode = curl_easy_perform(_curl);
167    curl_easy_setopt(_curl, CURLOPT_WRITEDATA, (void *)0);
168
169    return processResponse(responseCode, proxyAddress, fileName, sp);
170}
171
172osgDB::ReaderWriter::WriteResult EasyCurl::write(const std::string& proxyAddress, const std::string& fileName, StreamObject& sp, const osgDB::ReaderWriter::Options *options)
173{
174    setOptions(proxyAddress, fileName, sp, options);
175
176    char* postedContent = NULL;
177
178    // Copy data from istream into buffer.
179    long contentLength = 0;
180    const int bufferSize = 4096;
181    while(true)
182    {
183        postedContent = (char *)realloc(postedContent, contentLength + bufferSize);
184        size_t gotBytes = sp.read(postedContent + contentLength, bufferSize);
185        if (gotBytes == 0) break;
186        contentLength += gotBytes;
187    };
188
189    // Extract name and mime type of buffer to upload.
190    std::string uploadFileName = getFileNameFromURL(fileName);
191    std::string ext = osgDB::getLowerCaseFileExtension(uploadFileName);
192    std::string mimeType = getMimeTypeForExtension(ext);
193
194    // Construct "multipart/form-data" (RFC 1867) form elements for file upload.
195    struct curl_httppost* post = NULL;
196    struct curl_httppost* last = NULL;
197    curl_formadd(&post, &last,
198        CURLFORM_COPYNAME, "upload",
199        CURLFORM_CONTENTTYPE, mimeType.c_str(),
200        CURLFORM_BUFFER, uploadFileName.c_str(),
201        CURLFORM_BUFFERPTR, postedContent,
202        CURLFORM_BUFFERLENGTH, contentLength,
203        CURLFORM_END);
204
205    // Tell curl to use HTTP POST to send the form data.
206    curl_easy_setopt(_curl, CURLOPT_HTTPPOST, post);
207
208    CURLcode responseCode = curl_easy_perform(_curl);
209
210    if (post) curl_formfree(post);
211    if (postedContent) free(postedContent);
212    curl_easy_setopt(_curl, CURLOPT_HTTPPOST, (void *)0);
213    curl_easy_setopt(_curl, CURLOPT_HTTPGET, 1L);
214
215    curl_easy_setopt(_curl, CURLOPT_WRITEDATA, (void *)0);
216
217    if (processResponse(responseCode, proxyAddress, fileName, sp).success())
218    {
219        osgDB::ReaderWriter::WriteResult result(osgDB::ReaderWriter::WriteResult::FILE_SAVED);
220        std::stringstream* ss = dynamic_cast<std::stringstream*>(sp._outputStream);
221        if (ss)
222        {
223            // Put the server response in the message part of the result object.
224            result.message() = ss->str();
225        }
226        return result;
227    }
228    else
229    {
230        return osgDB::ReaderWriter::WriteResult::ERROR_IN_WRITING_FILE;
231    }
232}
233
234void EasyCurl::setOptions(const std::string& proxyAddress, const std::string& fileName, StreamObject& sp, const osgDB::ReaderWriter::Options *options)
235{
236    const osgDB::AuthenticationMap* authenticationMap = (options && options->getAuthenticationMap()) ?
237            options->getAuthenticationMap() :
238            osgDB::Registry::instance()->getAuthenticationMap();
239
240    // Set the timeout value here:
241    // Note that this has an effect only in a connection phase.
242    // WARNING: here we make the assumption that if someone starts using the timeouts settings
243    // he will not try to disable them afterwards (a value must be provided or the previous value is used).
244    if(_connectTimeout > 0)
245        curl_easy_setopt(_curl, CURLOPT_CONNECTTIMEOUT, _connectTimeout);
246    if(_timeout > 0)
247        curl_easy_setopt(_curl, CURLOPT_TIMEOUT, _timeout);
248
249    if(!proxyAddress.empty())
250    {
251        OSG_INFO<<"Setting proxy: "<<proxyAddress<<std::endl;
252        curl_easy_setopt(_curl, CURLOPT_PROXY, proxyAddress.c_str()); //Sets proxy address and port on libcurl
253    }
254
255    const osgDB::AuthenticationDetails* details = authenticationMap ?
256        authenticationMap->getAuthenticationDetails(fileName) :
257        0;
258
259    // configure/reset authentication if required.
260    if (details)
261    {
262        const std::string colon(":");
263        std::string password(details->username + colon + details->password);
264        curl_easy_setopt(_curl, CURLOPT_USERPWD, password.c_str());
265        _previousPassword = password;
266
267        // use for https.
268        // curl_easy_setopt(_curl, CURLOPT_KEYPASSWD, password.c_str());
269
270#if LIBCURL_VERSION_NUM >= 0x070a07
271        if (details->httpAuthentication != _previousHttpAuthentication)
272        {
273            curl_easy_setopt(_curl, CURLOPT_HTTPAUTH, details->httpAuthentication);
274            _previousHttpAuthentication = details->httpAuthentication;
275        }
276#endif
277
278    }
279    else
280    {
281        if (!_previousPassword.empty())
282        {
283            curl_easy_setopt(_curl, CURLOPT_USERPWD, 0);
284            _previousPassword.clear();
285        }
286
287#if LIBCURL_VERSION_NUM >= 0x070a07
288        // need to reset if previously set.
289        if (_previousHttpAuthentication!=0)
290        {
291            curl_easy_setopt(_curl, CURLOPT_HTTPAUTH, 0);
292            _previousHttpAuthentication = 0;
293        }
294#endif
295    }
296
297    curl_easy_setopt(_curl, CURLOPT_URL, fileName.c_str());
298    curl_easy_setopt(_curl, CURLOPT_WRITEDATA, (void *)&sp);
299}
300
301osgDB::ReaderWriter::ReadResult EasyCurl::processResponse(CURLcode res, const std::string& proxyAddress, const std::string& fileName, StreamObject& sp)
302{
303    if (res==0)
304    {
305
306#if LIBCURL_VERSION_NUM >= 0x070a07
307        long code;
308        if(!proxyAddress.empty())
309        {
310            curl_easy_getinfo(_curl, CURLINFO_HTTP_CONNECTCODE, &code);
311        }
312        else
313        {
314            curl_easy_getinfo(_curl, CURLINFO_RESPONSE_CODE, &code);
315        }
316
317        //If the code is greater than 400, there was an error
318        if (code >= 400)
319        {
320            osgDB::ReaderWriter::ReadResult::ReadStatus status;
321
322            //Distinguish between a client error and a server error
323            if (code < 500)
324            {
325                //A 400 level error indicates a client error
326                status = osgDB::ReaderWriter::ReadResult::FILE_NOT_FOUND;
327            }
328            else
329            {
330                //A 500 level error indicates a server error
331                status = osgDB::ReaderWriter::ReadResult::ERROR_IN_READING_FILE;
332            }
333
334            osgDB::ReaderWriter::ReadResult rr(status);
335
336            //Add the error code to the ReadResult
337            std::stringstream message;
338            message << "error code = " << code;
339
340            rr.message() = message.str();
341
342            return rr;
343        }
344#endif
345
346        // Store the mime-type, if any. (Note: CURL manages the buffer returned by
347        // this call.)
348        char* ctbuf = NULL;
349        if ( curl_easy_getinfo(_curl, CURLINFO_CONTENT_TYPE, &ctbuf) == 0 && ctbuf )
350        {
351            sp._resultMimeType = ctbuf;
352        }
353
354
355        return osgDB::ReaderWriter::ReadResult::FILE_LOADED;
356
357    }
358    else
359    {
360
361#if LIBCURL_VERSION_NUM >= 0x070c00
362         OSG_NOTICE<<"Error: libcurl read error, file="<<fileName<<" error = "<<curl_easy_strerror(res)<<std::endl;
363#else
364         OSG_NOTICE<<"Error: libcurl read error, file="<<fileName<<" error no = "<<res<<std::endl;
365#endif
366        return osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED;
367    }
368}
369
370///////////////////////////////////////////////////////////////////////////////////////////////////
371//
372//  ReaderWriterCURL
373//
374
375ReaderWriterCURL::ReaderWriterCURL()
376{
377    supportsProtocol("http","Read from http port using libcurl.");
378    supportsExtension("curl","Psuedo file extension, used to select curl plugin.");
379    supportsExtension("*","Passes all read files to other plugins to handle actual model loading.");
380    supportsOption("OSG_CURL_PROXY","Specify the http proxy.");
381    supportsOption("OSG_CURL_PROXYPORT","Specify the http proxy port.");
382    supportsOption("OSG_CURL_CONNECTTIMEOUT","Specify the connection timeout duration in seconds [default = 0 = not set].");
383    supportsOption("OSG_CURL_TIMEOUT","Specify the timeout duration of the whole transfer in seconds [default = 0 = not set].");
384}
385
386ReaderWriterCURL::~ReaderWriterCURL()
387{
388    //OSG_NOTICE<<"ReaderWriterCURL::~ReaderWriterCURL()"<<std::endl;
389}
390
391osgDB::ReaderWriter::WriteResult ReaderWriterCURL::writeFile(const osg::Object& obj, osgDB::ReaderWriter* rw, std::ostream& fout, const osgDB::ReaderWriter::Options *options) const
392{
393    const osg::HeightField* heightField = dynamic_cast<const osg::HeightField*>(&obj);
394    if (heightField) return rw->writeHeightField(*heightField, fout, options);
395
396    const osg::Node* node = dynamic_cast<const osg::Node*>(&obj);
397    if (node) return rw->writeNode(*node, fout, options);
398
399    const osg::Image* image = dynamic_cast<const osg::Image*>(&obj);
400    if (image) return rw->writeImage(*image, fout, options);
401
402    return rw->writeObject(obj, fout, options);
403}
404
405osgDB::ReaderWriter::WriteResult ReaderWriterCURL::writeFile(const osg::Object& obj, const std::string& fullFileName, const Options *options) const
406{
407    if (!osgDB::containsServerAddress(fullFileName))
408    {
409        return WriteResult::FILE_NOT_HANDLED;
410    }
411
412    std::stringstream requestBuffer; // Buffer to be filled then output via http request.
413    std::stringstream responseBuffer; // Buffer to contain content of http response.
414
415    // Serialize obj into an std::stringstream buffer which will be uploaded via HTTP post request.
416    std::string fileName = EasyCurl::getFileNameFromURL(fullFileName);
417    std::string ext = osgDB::getLowerCaseFileExtension(fileName);
418    osgDB::ReaderWriter* writer = osgDB::Registry::instance()->getReaderWriterForExtension(ext);
419    if (!writer) return WriteResult::FILE_NOT_HANDLED;
420    osgDB::ReaderWriter::WriteResult result = writeFile(obj, writer, requestBuffer, options);
421    if (!result.success()) return result;
422
423    // Configure curl connection options.
424    std::string proxyAddress;
425    long connectTimeout = 0;
426    long timeout = 0;
427    getConnectionOptions(options, proxyAddress, connectTimeout, timeout);
428    EasyCurl::StreamObject sp(&responseBuffer, &requestBuffer, std::string());
429    EasyCurl& easyCurl = getEasyCurl();
430    easyCurl.setConnectionTimeout(connectTimeout);
431    easyCurl.setTimeout(timeout);
432
433    // Output requestBuffer via curl, and return responseBuffer in message of result.
434    return easyCurl.write(proxyAddress, fullFileName, sp, options);
435}
436
437osgDB::ReaderWriter::ReadResult ReaderWriterCURL::readFile(ObjectType objectType, osgDB::ReaderWriter* rw, std::istream& fin, const osgDB::ReaderWriter::Options *options) const
438{
439    switch(objectType)
440    {
441    case(OBJECT): return rw->readObject(fin,options);
442    case(ARCHIVE): return rw->openArchive(fin,options);
443    case(IMAGE): return rw->readImage(fin,options);
444    case(HEIGHTFIELD): return rw->readHeightField(fin,options);
445    case(NODE): return rw->readNode(fin,options);
446    default: break;
447    }
448    return ReadResult::FILE_NOT_HANDLED;
449}
450
451void ReaderWriterCURL::getConnectionOptions(const osgDB::ReaderWriter::Options *options, std::string& proxyAddress, long& connectTimeout, long& timeout) const
452{
453    if (options)
454    {
455        std::istringstream iss(options->getOptionString());
456        std::string opt, optProxy, optProxyPort;
457        while (iss >> opt)
458        {
459            int index = opt.find( "=" );
460            if( opt.substr( 0, index ) == "OSG_CURL_PROXY" )
461                optProxy = opt.substr( index+1 );
462            else if( opt.substr( 0, index ) == "OSG_CURL_PROXYPORT" )
463                optProxyPort = opt.substr( index+1 );
464            else if( opt.substr( 0, index ) == "OSG_CURL_CONNECTTIMEOUT" )
465                connectTimeout = atol(opt.substr( index+1 ).c_str()); // this will return 0 in case of improper format.
466            else if( opt.substr( 0, index ) == "OSG_CURL_TIMEOUT" )
467                timeout = atol(opt.substr( index+1 ).c_str()); // this will return 0 in case of improper format.
468        }
469
470        //Setting Proxy by OSG Options
471        if(!optProxy.empty())
472        {
473            if(!optProxyPort.empty())
474                proxyAddress = optProxy + ":" + optProxyPort;
475            else
476                proxyAddress = optProxy + ":8080"; //Port not found, using default
477        }
478    }
479
480    const char* proxyEnvAddress = getenv("OSG_CURL_PROXY");
481    if (proxyEnvAddress) //Env Proxy Settings
482    {
483        const char* proxyEnvPort = getenv("OSG_CURL_PROXYPORT"); //Searching Proxy Port on Env
484
485        if(proxyEnvPort)
486            proxyAddress = std::string(proxyEnvAddress) + ":" + std::string(proxyEnvPort);
487        else
488            proxyAddress = std::string(proxyEnvAddress) + ":8080"; //Default
489    }
490
491}
492
493osgDB::ReaderWriter::ReadResult ReaderWriterCURL::readFile(ObjectType objectType, const std::string& fullFileName, const osgDB::ReaderWriter::Options *options) const
494{
495    std::string fileName(fullFileName);
496    std::string ext = osgDB::getFileExtension(fullFileName);
497    bool curl_ext = ext=="curl";
498    if (curl_ext)
499    {
500        fileName = osgDB::getNameLessExtension(fullFileName);
501        ext = osgDB::getFileExtension(fileName);
502    }
503
504    if (!osgDB::containsServerAddress(fileName))
505    {
506        if (options && !options->getDatabasePathList().empty())
507        {
508            if (osgDB::containsServerAddress(options->getDatabasePathList().front()))
509            {
510                std::string newFileName = options->getDatabasePathList().front() + "/" + fileName;
511
512                return readFile(objectType, newFileName,options);
513            }
514        }
515
516        // if user has explictly specified curl then we don't about at this point,
517        // instead assume the curl can read it any way, if it doesn't explictly
518        // specify curl then we assume that the file is a local file and not appropriate
519        // for the curl plugin to load.
520        if (!curl_ext) return ReadResult::FILE_NOT_HANDLED;
521    }
522
523    OSG_INFO<<"ReaderWriterCURL::readFile("<<fullFileName<<")"<<std::endl;
524
525    std::string proxyAddress;
526    long connectTimeout = 0;
527    long timeout = 0;
528    getConnectionOptions(options, proxyAddress, connectTimeout, timeout);
529
530    bool uncompress = false;
531
532    if (ext=="gz" || ext=="osgz" || ext=="ivez")
533    {
534        OSG_INFO<<"CURL: Compressed file type "<<ext<<std::endl;
535
536        #ifndef USE_ZLIB
537            // don't have zlib so can't compile compressed formats
538            return ReadResult::FILE_NOT_HANDLED;
539        #endif
540
541        uncompress = true;
542
543        if (ext=="gz")
544        {
545            ext = osgDB::getFileExtension(osgDB::getNameLessExtension(fileName));
546        }
547        else if (ext=="osgz")
548        {
549            ext = "osg";
550        }
551        else if (ext=="ivez")
552        {
553            ext = "ive";
554        }
555
556        OSG_INFO<<"CURL: assuming file type "<<ext<<std::endl;
557    }
558
559    std::stringstream buffer;
560
561    EasyCurl::StreamObject sp(&buffer, NULL, std::string());
562    EasyCurl& easyCurl = getEasyCurl();
563
564    // setup the timeouts:
565    easyCurl.setConnectionTimeout(connectTimeout);
566    easyCurl.setTimeout(timeout);
567
568    ReadResult curlResult = easyCurl.read(proxyAddress, fileName, sp, options);
569
570    if (curlResult.status()==ReadResult::FILE_LOADED)
571    {
572        OSG_INFO<<"CURL: ReadResult::FILE_LOADED "<<std::endl;
573
574        // Try to find a reader by file extension. If this fails, we will fetch the file
575        // anyway and try to get a reader via mime-type.
576        osgDB::ReaderWriter *reader =
577            osgDB::Registry::instance()->getReaderWriterForExtension( ext );
578
579        // If we do not already have a ReaderWriter, try to find one based on the
580        // mime-type:
581        if ( !reader )
582        {
583            std::string mimeType = easyCurl.getResultMimeType(sp);
584            OSG_INFO << "CURL: Looking up extension for mime-type " << mimeType << std::endl;
585            if ( mimeType.length() > 0 )
586            {
587                reader = osgDB::Registry::instance()->getReaderWriterForMimeType(mimeType);
588            }
589        }
590
591        // If there is still no reader, fail.
592        if ( !reader )
593        {
594            OSG_NOTICE<<"Error: No ReaderWriter for file "<<fileName<<std::endl;
595            return ReadResult::FILE_NOT_HANDLED;
596        }
597
598        osg::ref_ptr<Options> local_opt = options ?
599            static_cast<Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) :
600            new Options;
601
602        local_opt->getDatabasePathList().push_front(osgDB::getFilePath(fileName));
603        local_opt->setPluginStringData("STREAM_FILENAME",osgDB::getSimpleFileName(fileName));
604        local_opt->setPluginStringData("filename",fileName);
605
606        if (uncompress)
607        {
608            OSG_INFO<<"Curl:: plugin uncompressing "<<fileName<<std::endl;
609
610            std::string uncompressed;
611            if (!read(buffer, uncompressed))
612            {
613                return ReadResult::FILE_NOT_HANDLED;
614            }
615
616            buffer.str(uncompressed);
617        }
618
619        ReadResult readResult = readFile(objectType, reader, buffer, local_opt.get() );
620
621        local_opt->getDatabasePathList().pop_front();
622
623        return readResult;
624    }
625    else
626    {
627        OSG_INFO<<"CURL: not loading successfully "<<std::endl;
628        return curlResult;
629    }
630}
631
632#ifdef USE_ZLIB
633
634#include <zlib.h>
635
636bool ReaderWriterCURL::read(std::istream& fin, std::string& destination) const
637{
638    #define CHUNK 16384
639
640    int ret;
641    unsigned have;
642    z_stream strm;
643    unsigned char in[CHUNK];
644    unsigned char out[CHUNK];
645
646    /* allocate inflate state */
647    strm.zalloc = Z_NULL;
648    strm.zfree = Z_NULL;
649    strm.opaque = Z_NULL;
650    strm.avail_in = 0;
651    strm.next_in = Z_NULL;
652    ret = inflateInit2(&strm,
653                       15 + 32 // autodected zlib or gzip header
654                       );
655    if (ret != Z_OK)
656        return false;
657
658    /* decompress until deflate stream ends or end of file */
659    do {
660
661        strm.avail_in = fin.readsome((char*)in, CHUNK);
662
663        if (fin.fail())
664        {
665            (void)inflateEnd(&strm);
666            return false;
667        }
668        if (strm.avail_in == 0)
669            break;
670        strm.next_in = in;
671
672        /* run inflate() on input until output buffer not full */
673        do {
674            strm.avail_out = CHUNK;
675            strm.next_out = out;
676            ret = inflate(&strm, Z_NO_FLUSH);
677
678            switch (ret) {
679            case Z_NEED_DICT:
680            case Z_DATA_ERROR:
681            case Z_MEM_ERROR:
682                (void)inflateEnd(&strm);
683                return false;
684            }
685            have = CHUNK - strm.avail_out;
686
687            destination.append((char*)out, have);
688
689        } while (strm.avail_out == 0);
690
691        /* done when inflate() says it's done */
692    } while (ret != Z_STREAM_END);
693
694    /* clean up and return */
695    (void)inflateEnd(&strm);
696    return ret == Z_STREAM_END ? true : false;
697}
698#else
699bool ReaderWriterCURL::read(std::istream& fin, std::string& destination) const
700{
701    return false;
702}
703#endif
704
705bool ReaderWriterCURL::fileExists(const std::string& filename, const osgDB::Options* options) const
706{
707    if (osgDB::containsServerAddress(filename))
708    {
709        OSG_NOTICE<<"Checking if file exists using curl plugin: "<<filename<<std::endl;
710
711        ReadResult result = readFile(OBJECT,filename,options);
712        return result.status()==osgDB::ReaderWriter::ReadResult::FILE_LOADED;
713    }
714    else
715    {
716        return ReaderWriter::fileExists(filename, options);
717    }
718}
719
720
721// now register with Registry to instantiate the above
722// reader/writer.
723REGISTER_OSGPLUGIN(curl, ReaderWriterCURL)
Note: See TracBrowser for help on using the browser.