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

Revision 11272, 12.5 kB (checked in by robert, 4 years ago)

From Chuck Seberino, "have a fix for the reading code in trunk/src/osgPlugins/gz/ReaderWriterGZ.cpp. It seems that the std::istream::readsome method on windows is a no-op (for files. After much head scratching and research I was able to figure out what was going on. I am submitting a fix to replace readsome with read() and gcount(). This change is for all platforms. The previous implementation works fine under linux and OSX, so if you would rather keep things the way they are you can just #ifdef for non-WIN32.

I also added openmode flags to the ifstream constructor, since they were needed to get proper reading as well as a typo fix."

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(), std::ios::binary|std::ios::in);
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 // autodetected 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        fin.read((char*)in, CHUNK);
263        strm.avail_in = fin.gcount();
264
265        if (fin.fail())
266        {
267            (void)inflateEnd(&strm);
268            return false;
269        }
270        if (strm.avail_in == 0)
271            break;
272        strm.next_in = in;
273
274        /* run inflate() on input until output buffer not full */
275        do {
276            strm.avail_out = CHUNK;
277            strm.next_out = out;
278            ret = inflate(&strm, Z_NO_FLUSH);
279
280            switch (ret) {
281            case Z_NEED_DICT:
282            case Z_DATA_ERROR:
283            case Z_MEM_ERROR:
284                (void)inflateEnd(&strm);
285                return false;
286            }
287            have = CHUNK - strm.avail_out;
288
289            destination.append((char*)out, have);
290           
291        } while (strm.avail_out == 0);
292
293        /* done when inflate() says it's done */
294    } while (ret != Z_STREAM_END);
295
296    /* clean up and return */
297    (void)inflateEnd(&strm);
298    return ret == Z_STREAM_END ? true : false;
299}
300
301bool ReaderWriterGZ::write(std::ostream& fout, const std::string& source) const
302{
303    int ret, flush = Z_FINISH;
304    unsigned have;
305    z_stream strm;
306    unsigned char out[CHUNK];
307   
308    int level = 6;
309    int stategy = Z_DEFAULT_STRATEGY; // looks to be the best for .osg/.ive files
310    //int stategy = Z_FILTERED;
311    //int stategy = Z_HUFFMAN_ONLY;
312    //int stategy = Z_RLE;
313
314    /* allocate deflate state */
315    strm.zalloc = Z_NULL;
316    strm.zfree = Z_NULL;
317    strm.opaque = Z_NULL;
318    ret = deflateInit2(&strm,
319                       level,
320                       Z_DEFLATED,
321                       15+16, // +16 to use gzip encoding
322                       8, // default
323                       stategy);
324    if (ret != Z_OK)
325    return false;
326
327    strm.avail_in = source.size();
328    strm.next_in = (Bytef*)(&(*source.begin()));
329
330    /* run deflate() on input until output buffer not full, finish
331       compression if all of source has been read in */
332    do {
333        strm.avail_out = CHUNK;
334        strm.next_out = out;
335        ret = deflate(&strm, flush);    /* no bad return value */
336
337        if (ret == Z_STREAM_ERROR)
338        {
339            osg::notify(osg::NOTICE)<<"Z_STREAM_ERROR"<<std::endl;
340            return false;
341        }
342
343        have = CHUNK - strm.avail_out;
344
345        if (have>0) fout.write((const char*)out, have);
346       
347        if (fout.fail())
348        {
349            (void)deflateEnd(&strm);
350            return false;
351        }
352    } while (strm.avail_out == 0);
353
354    /* clean up and return */
355    (void)deflateEnd(&strm);
356    return true;
357}
358
359
360// now register with Registry to instantiate the above
361// reader/writer.
362REGISTER_OSGPLUGIN(GZ, ReaderWriterGZ)
Note: See TracBrowser for help on using the browser.