root/OpenSceneGraph/trunk/src/osgPlugins/gz/ReaderWriterGZ.cpp @ 10465

Revision 10465, 12.4 kB (checked in by robert, 5 years ago)

Quietened down debug messages, and added early return when filename contains server address.

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/FileNameUtils>
16#include <osgDB/ReadFile>
17#include <osgDB/WriteFile>
18#include <osgDB/Registry>
19
20#include <iostream>
21#include <sstream>
22#include <fstream>
23#include <iterator>
24
25#include <zlib.h>
26
27///////////////////////////////////////////////////////////////////////////////////////////////////
28//
29//  ReaderWriterGZ
30//
31class ReaderWriterGZ : public osgDB::ReaderWriter
32{
33    public:
34   
35        enum ObjectType
36        {
37            OBJECT,
38            ARCHIVE,
39            IMAGE,
40            HEIGHTFIELD,
41            NODE
42        };
43
44        ReaderWriterGZ();
45     
46        ~ReaderWriterGZ();
47
48        virtual const char* className() const { return "HTTP Protocol Model Reader"; }
49                                                                                           
50        virtual ReadResult openArchive(const std::string& fileName,ArchiveStatus status, unsigned int , const Options* options) const
51        {
52            if (status!=READ) return ReadResult(ReadResult::FILE_NOT_HANDLED);
53            else return readFile(ARCHIVE,fileName,options);
54        }
55
56        virtual ReadResult readObject(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
57        {
58            return readFile(OBJECT,fileName,options);
59        }
60                                                                                           
61        virtual ReadResult readImage(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
62        {
63            return readFile(IMAGE,fileName,options);
64        }
65
66        virtual ReadResult readHeightField(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
67        {
68            return readFile(HEIGHTFIELD,fileName,options);
69        }
70
71        virtual ReadResult readNode(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
72        {
73            return readFile(NODE,fileName,options);
74        }
75
76        ReadResult readFile(ObjectType objectType, osgDB::ReaderWriter* rw, std::istream& fin, const osgDB::ReaderWriter::Options* options) const;
77       
78        ReadResult readFile(ObjectType objectType, const std::string& fullFileName, const osgDB::ReaderWriter::Options* options) const;
79
80
81
82        virtual WriteResult writeObject(const osg::Object& obj, const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
83        {
84            return writeFile(OBJECT, &obj, fileName, options);
85        }
86                                                                                           
87        virtual WriteResult writeImage(const osg::Image& image, const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
88        {
89            return writeFile(IMAGE, &image, fileName, options);
90        }
91
92        virtual WriteResult writeHeightField(const osg::HeightField& hf, const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
93        {
94            return writeFile(HEIGHTFIELD, &hf, fileName, options);
95        }
96
97        virtual WriteResult writeNode(const osg::Node& node, const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
98        {
99            return writeFile(NODE, &node, fileName,options);
100        }
101
102        WriteResult writeFile(ObjectType objectType, const osg::Object* object, osgDB::ReaderWriter* rw, std::ostream& fin, const osgDB::ReaderWriter::Options* options) const;
103       
104        WriteResult writeFile(ObjectType objectType, const osg::Object* object, const std::string& fullFileName, const osgDB::ReaderWriter::Options* options) const;
105
106
107        bool read(std::istream& fin, std::string& destination) const;
108        bool write(std::ostream& fout, const std::string& source) const;
109       
110
111};
112
113ReaderWriterGZ::ReaderWriterGZ()
114{
115    // osg::notify(osg::NOTICE)<<"ReaderWriterGZ::ReaderWriterGZ()"<<std::endl;
116
117    supportsExtension("osgz","Compressed .osg file extension.");
118    supportsExtension("ivez","Compressed .ive file extension.");
119    supportsExtension("gz","Compressed file extension.");
120}
121
122ReaderWriterGZ::~ReaderWriterGZ()
123{
124    // osg::notify(osg::NOTICE)<<"ReaderWriterGZ::~ReaderWriterGZ()"<<std::endl;
125}
126
127osgDB::ReaderWriter::ReadResult ReaderWriterGZ::readFile(ObjectType objectType, osgDB::ReaderWriter* rw, std::istream& fin, const osgDB::ReaderWriter::Options *options) const
128{
129    switch(objectType)
130    {
131        case(OBJECT): return rw->readObject(fin,options);
132        case(ARCHIVE): return rw->openArchive(fin,options);
133        case(IMAGE): return rw->readImage(fin,options);
134        case(HEIGHTFIELD): return rw->readHeightField(fin,options);
135        case(NODE): return rw->readNode(fin,options);
136        default: break;
137    }
138    return ReadResult::FILE_NOT_HANDLED;
139}
140
141osgDB::ReaderWriter::ReadResult ReaderWriterGZ::readFile(ObjectType objectType, const std::string& fullFileName, const osgDB::ReaderWriter::Options *options) const
142{
143    std::string ext = osgDB::getLowerCaseFileExtension(fullFileName);
144    if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
145
146    if (osgDB::containsServerAddress(fullFileName)) return ReadResult::FILE_NOT_HANDLED;
147
148    osgDB::ReaderWriter* rw = 0;
149
150    if (osgDB::equalCaseInsensitive(ext,"osgz"))
151    { 
152        rw = osgDB::Registry::instance()->getReaderWriterForExtension("osg");
153        osg::notify(osg::INFO)<<"osgz ReaderWriter "<<rw<<std::endl;
154    }
155    else if (osgDB::equalCaseInsensitive(ext,"ivez"))
156    {
157        rw = osgDB::Registry::instance()->getReaderWriterForExtension("ive");
158        osg::notify(osg::INFO)<<"ivez ReaderWriter "<<rw<<std::endl;
159    }
160    else
161    {
162        std::string baseFileName = osgDB::getNameLessExtension(fullFileName);       
163        std::string baseExt = osgDB::getLowerCaseFileExtension(baseFileName);
164        rw = osgDB::Registry::instance()->getReaderWriterForExtension(baseExt);
165        osg::notify(osg::INFO)<<baseExt<<" ReaderWriter "<<rw<<std::endl;
166    }
167
168
169    std::string fileName = osgDB::findDataFile( fullFileName, options );
170    if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
171
172    // code for setting up the database path so that internally referenced file are searched for on relative paths.
173    osg::ref_ptr<Options> local_opt = options ? static_cast<Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options;
174    local_opt->getDatabasePathList().push_front(osgDB::getFilePath(fileName));
175
176    std::ifstream fin(fileName.c_str());
177    if (!fin) return ReadResult::ERROR_IN_READING_FILE;
178   
179
180    std::string dest;
181    read(fin, dest);
182
183    std::stringstream strstream(dest);
184
185    return readFile(objectType, rw, strstream, local_opt.get());
186}
187
188
189osgDB::ReaderWriter::WriteResult ReaderWriterGZ::writeFile(ObjectType objectType, const osg::Object* object, osgDB::ReaderWriter* rw, std::ostream& fout, const osgDB::ReaderWriter::Options *options) const
190{
191    switch(objectType)
192    {
193        case(OBJECT): return rw->writeObject(*object, fout, options);
194        case(IMAGE): return rw->writeImage(*(dynamic_cast<const osg::Image*>(object)), fout, options);
195        case(HEIGHTFIELD): return rw->writeHeightField(*(dynamic_cast<const osg::HeightField*>(object)), fout, options);
196        case(NODE): return rw->writeNode(*(dynamic_cast<const osg::Node*>(object)), fout,options);
197        default: break;
198    }
199    return WriteResult::FILE_NOT_HANDLED;
200}
201
202osgDB::ReaderWriter::WriteResult ReaderWriterGZ::writeFile(ObjectType objectType, const osg::Object* object, const std::string& fullFileName, const osgDB::ReaderWriter::Options *options) const
203{
204    std::string ext = osgDB::getLowerCaseFileExtension(fullFileName);
205    if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED;
206
207    osgDB::ReaderWriter* rw = 0;
208
209    if (osgDB::equalCaseInsensitive(ext,"osgz"))
210    { 
211        rw = osgDB::Registry::instance()->getReaderWriterForExtension("osg");
212        osg::notify(osg::NOTICE)<<"osgz ReaderWriter "<<rw<<std::endl;
213    }
214    else if (osgDB::equalCaseInsensitive(ext,"ivez"))
215    {
216        rw = osgDB::Registry::instance()->getReaderWriterForExtension("ive");
217        osg::notify(osg::NOTICE)<<"ivez ReaderWriter "<<rw<<std::endl;
218    }
219    else
220    {
221        std::string baseFileName = osgDB::getNameLessExtension(fullFileName);       
222        std::string baseExt = osgDB::getLowerCaseFileExtension(baseFileName);
223        rw = osgDB::Registry::instance()->getReaderWriterForExtension(baseExt);
224        osg::notify(osg::NOTICE)<<baseExt<<" ReaderWriter "<<rw<<std::endl;
225    }
226   
227    std::stringstream strstream;
228    osgDB::ReaderWriter::WriteResult writeResult = writeFile(objectType, object, rw, strstream, options);
229   
230    std::ofstream fout(fullFileName.c_str());
231   
232    write(fout,strstream.str());
233   
234    return writeResult;
235}
236
237#define CHUNK 16384
238
239bool ReaderWriterGZ::read(std::istream& fin, std::string& destination) const
240{
241    int ret;
242    unsigned have;
243    z_stream strm;
244    unsigned char in[CHUNK];
245    unsigned char out[CHUNK];
246
247    /* allocate inflate state */
248    strm.zalloc = Z_NULL;
249    strm.zfree = Z_NULL;
250    strm.opaque = Z_NULL;
251    strm.avail_in = 0;
252    strm.next_in = Z_NULL;
253    ret = inflateInit2(&strm,
254                       15 + 32 // autodected zlib or gzip header
255                       );
256    if (ret != Z_OK)
257        return false;
258
259    /* decompress until deflate stream ends or end of file */
260    do {
261
262        strm.avail_in = fin.readsome((char*)in, CHUNK);
263
264        if (fin.fail())
265        {
266            (void)inflateEnd(&strm);
267            return false;
268        }
269        if (strm.avail_in == 0)
270            break;
271        strm.next_in = in;
272
273        /* run inflate() on input until output buffer not full */
274        do {
275            strm.avail_out = CHUNK;
276            strm.next_out = out;
277            ret = inflate(&strm, Z_NO_FLUSH);
278
279            switch (ret) {
280            case Z_NEED_DICT:
281            case Z_DATA_ERROR:
282            case Z_MEM_ERROR:
283                (void)inflateEnd(&strm);
284                return false;
285            }
286            have = CHUNK - strm.avail_out;
287
288            destination.append((char*)out, have);
289           
290        } while (strm.avail_out == 0);
291
292        /* done when inflate() says it's done */
293    } while (ret != Z_STREAM_END);
294
295    /* clean up and return */
296    (void)inflateEnd(&strm);
297    return ret == Z_STREAM_END ? true : false;
298}
299
300bool ReaderWriterGZ::write(std::ostream& fout, const std::string& source) const
301{
302    int ret, flush = Z_FINISH;
303    unsigned have;
304    z_stream strm;
305    unsigned char out[CHUNK];
306   
307    int level = 6;
308    int stategy = Z_DEFAULT_STRATEGY; // looks to be the best for .osg/.ive files
309    //int stategy = Z_FILTERED;
310    //int stategy = Z_HUFFMAN_ONLY;
311    //int stategy = Z_RLE;
312
313    /* allocate deflate state */
314    strm.zalloc = Z_NULL;
315    strm.zfree = Z_NULL;
316    strm.opaque = Z_NULL;
317    ret = deflateInit2(&strm,
318                       level,
319                       Z_DEFLATED,
320                       15+16, // +16 to use gzip encoding
321                       8, // default
322                       stategy);
323    if (ret != Z_OK)
324    return false;
325
326    strm.avail_in = source.size();
327    strm.next_in = (Bytef*)(&(*source.begin()));
328
329    /* run deflate() on input until output buffer not full, finish
330       compression if all of source has been read in */
331    do {
332        strm.avail_out = CHUNK;
333        strm.next_out = out;
334        ret = deflate(&strm, flush);    /* no bad return value */
335
336        if (ret == Z_STREAM_ERROR)
337        {
338            osg::notify(osg::NOTICE)<<"Z_STREAM_ERROR"<<std::endl;
339            return false;
340        }
341
342        have = CHUNK - strm.avail_out;
343
344        if (have>0) fout.write((const char*)out, have);
345       
346        if (fout.fail())
347        {
348            (void)deflateEnd(&strm);
349            return false;
350        }
351    } while (strm.avail_out == 0);
352
353    /* clean up and return */
354    (void)deflateEnd(&strm);
355    return true;
356}
357
358
359// now register with Registry to instantiate the above
360// reader/writer.
361REGISTER_OSGPLUGIN(GZ, ReaderWriterGZ)
Note: See TracBrowser for help on using the browser.