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

Revision 13041, 12.0 kB (checked in by robert, 2 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/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_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_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_INFO<<"osgz ReaderWriter "<<rw<<std::endl;
154    }
155    else if (osgDB::equalCaseInsensitive(ext,"ivez"))
156    {
157        rw = osgDB::Registry::instance()->getReaderWriterForExtension("ive");
158        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_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    osgDB::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_NOTICE<<"osgz ReaderWriter "<<rw<<std::endl;
213    }
214    else if (osgDB::equalCaseInsensitive(ext,"ivez"))
215    {
216        rw = osgDB::Registry::instance()->getReaderWriterForExtension("ive");
217        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_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    osgDB::ofstream fout(fullFileName.c_str(), std::ios::binary|std::ios::out);
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.bad())
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_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.