diff --git a/include/osgDB/ConvertBase64 b/include/osgDB/ConvertBase64 new file mode 100644 index 000000000..b6950f94c --- /dev/null +++ b/include/osgDB/ConvertBase64 @@ -0,0 +1,102 @@ +/* -*-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. +*/ + +/* This file is derived from the libb64 project which itself was released to public domain. + * For details, see http://sourceforge.net/projects/libb64. Original code by Chris Venter + * c++ wrapper for a base64 encoding and decoding algorithm +*/ + +#ifndef OSGDB_CONVERTBASE64_H +#define OSGDB_CONVERTBASE64_H 1 + +#include +#include +#include + +#include + +namespace osgDB +{ + const int BUFFERSIZE = 8192; + + typedef enum + { + step_a, step_b, step_c, step_d + } base64_decodestep; + + typedef enum + { + step_A, step_B, step_C + } base64_encodestep; + + typedef struct + { + base64_encodestep step; + char result; + int stepcount; + } base64_encodestate; + + typedef struct + { + base64_decodestep step; + char plainchar; + } base64_decodestate; + + class OSGDB_EXPORT Base64encoder + { + public: + Base64encoder(int buffersize_in = BUFFERSIZE) + : _buffersize(buffersize_in) + {} + + int encode(char value_in); + + int encode(const char* code_in, const int length_in, char* plaintext_out); + + int encode_end(char* plaintext_out); + + void encode(std::istream& istream_in, std::ostream& ostream_in); + + void encode(const char* chars_in, int length_in, std::string& code_out); + + private: + base64_encodestate _state; + int _buffersize; + }; + + class OSGDB_EXPORT Base64decoder + { + public: + Base64decoder(int buffersize_in = BUFFERSIZE) + : _buffersize(buffersize_in) + {} + + int decode(char value_in); + + int decode(const char* code_in, const int length_in, char* plaintext_out); + + void decode(std::istream& istream_in, std::ostream& ostream_in); + + // Decode strings, returns one char* of appropriate size + // Note that deallocation of char* is up to the caller of this method + char* decode(const std::vector& str_in, std::vector& pos_out); + + private: + base64_decodestate _state; + int _buffersize; + }; + +} // namespace osgDB + +#endif // BASE64_DECODE_H + diff --git a/src/osgDB/CMakeLists.txt b/src/osgDB/CMakeLists.txt index cb6e46fd1..1e9b6d73a 100644 --- a/src/osgDB/CMakeLists.txt +++ b/src/osgDB/CMakeLists.txt @@ -53,6 +53,7 @@ SET(TARGET_H ${HEADER_PATH}/AuthenticationMap ${HEADER_PATH}/Callbacks ${HEADER_PATH}/ClassInterface + ${HEADER_PATH}/ConvertBase64 ${HEADER_PATH}/ConvertUTF ${HEADER_PATH}/DatabasePager ${HEADER_PATH}/DatabaseRevisions @@ -91,6 +92,7 @@ SET(TARGET_SRC AuthenticationMap.cpp Callbacks.cpp ClassInterface.cpp + ConvertBase64.cpp ConvertUTF.cpp DatabasePager.cpp DatabaseRevisions.cpp diff --git a/src/osgDB/ConvertBase64.cpp b/src/osgDB/ConvertBase64.cpp new file mode 100644 index 000000000..cbd1ae62d --- /dev/null +++ b/src/osgDB/ConvertBase64.cpp @@ -0,0 +1,326 @@ +/* -*-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. +*/ + +/* This file is derived from the libb64 project which itself was released to public domain. + * For details, see http://sourceforge.net/projects/libb64. Original code by Chris Venter + * c++ wrapper for a base64 encoding and decoding algorithm +*/ + +#include + +#include +#include + +namespace osgDB +{ + + const int CHARS_PER_LINE = 72; + + int base64_decode_value(char value_in) + { + static const char decoding[] = {62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-2,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51}; + static const char decoding_size = sizeof(decoding); + value_in -= 43; + if (value_in < 0 || value_in > decoding_size) return -1; + return decoding[(int)value_in]; + } + + void base64_init_decodestate(base64_decodestate* state_in) + { + state_in->step = step_a; + state_in->plainchar = 0; + } + + int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in) + { + const char* codechar = code_in; + char* plainchar = plaintext_out; + char fragment; + + *plainchar = state_in->plainchar; + + switch (state_in->step) + { + while (1) + { + case step_a: + do { + if (codechar == code_in+length_in) + { + state_in->step = step_a; + state_in->plainchar = *plainchar; + return plainchar - plaintext_out; + } + fragment = (char)base64_decode_value(*codechar++); + } while (fragment < 0); + *plainchar = (fragment & 0x03f) << 2; + case step_b: + do { + if (codechar == code_in+length_in) + { + state_in->step = step_b; + state_in->plainchar = *plainchar; + return plainchar - plaintext_out; + } + fragment = (char)base64_decode_value(*codechar++); + } while (fragment < 0); + *plainchar++ |= (fragment & 0x030) >> 4; + *plainchar = (fragment & 0x00f) << 4; + case step_c: + do { + if (codechar == code_in+length_in) + { + state_in->step = step_c; + state_in->plainchar = *plainchar; + return plainchar - plaintext_out; + } + fragment = (char)base64_decode_value(*codechar++); + } while (fragment < 0); + *plainchar++ |= (fragment & 0x03c) >> 2; + *plainchar = (fragment & 0x003) << 6; + case step_d: + do { + if (codechar == code_in+length_in) + { + state_in->step = step_d; + state_in->plainchar = *plainchar; + return plainchar - plaintext_out; + } + fragment = (char)base64_decode_value(*codechar++); + } while (fragment < 0); + *plainchar++ |= (fragment & 0x03f); + } + } + /* control should not reach here */ + return plainchar - plaintext_out; + } + + void base64_init_encodestate(base64_encodestate* state_in) + { + state_in->step = step_A; + state_in->result = 0; + state_in->stepcount = 0; + } + + char base64_encode_value(char value_in) + { + static const char* encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + if (value_in > 63) return '='; + return encoding[(int)value_in]; + } + + int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in) + { + const char* plainchar = plaintext_in; + const char* const plaintextend = plaintext_in + length_in; + char* codechar = code_out; + char result; + char fragment; + + result = state_in->result; + + switch (state_in->step) + { + while (1) + { + case step_A: + if (plainchar == plaintextend) + { + state_in->result = result; + state_in->step = step_A; + return codechar - code_out; + } + fragment = *plainchar++; + result = (fragment & 0x0fc) >> 2; + *codechar++ = base64_encode_value(result); + result = (fragment & 0x003) << 4; + case step_B: + if (plainchar == plaintextend) + { + state_in->result = result; + state_in->step = step_B; + return codechar - code_out; + } + fragment = *plainchar++; + result |= (fragment & 0x0f0) >> 4; + *codechar++ = base64_encode_value(result); + result = (fragment & 0x00f) << 2; + case step_C: + if (plainchar == plaintextend) + { + state_in->result = result; + state_in->step = step_C; + return codechar - code_out; + } + fragment = *plainchar++; + result |= (fragment & 0x0c0) >> 6; + *codechar++ = base64_encode_value(result); + result = (fragment & 0x03f) >> 0; + *codechar++ = base64_encode_value(result); + + ++(state_in->stepcount); + if (state_in->stepcount == CHARS_PER_LINE/4) + { + *codechar++ = '\n'; + state_in->stepcount = 0; + } + } + } + /* control should not reach here */ + return codechar - code_out; + } + + int base64_encode_blockend(char* code_out, base64_encodestate* state_in) + { + char* codechar = code_out; + + switch (state_in->step) + { + case step_B: + *codechar++ = base64_encode_value(state_in->result); + *codechar++ = '='; + *codechar++ = '='; + break; + case step_C: + *codechar++ = base64_encode_value(state_in->result); + *codechar++ = '='; + break; + case step_A: + break; + } + *codechar++ = '\n'; + + return codechar - code_out; + } + + int Base64encoder::encode(char value_in) + { + return base64_encode_value(value_in); + } + + int Base64encoder::encode(const char* code_in, const int length_in, char* plaintext_out) + { + return base64_encode_block(code_in, length_in, plaintext_out, &_state); + } + + int Base64encoder::encode_end(char* plaintext_out) + { + return base64_encode_blockend(plaintext_out, &_state); + } + + void Base64encoder::encode(std::istream& istream_in, std::ostream& ostream_in) + { + base64_init_encodestate(&_state); + + const int N = _buffersize; + char* plaintext = new char[N]; + char* code = new char[2*N]; + int plainlength; + int codelength; + + do + { + istream_in.read(plaintext, N); + plainlength = istream_in.gcount(); + + codelength = encode(plaintext, plainlength, code); + ostream_in.write(code, codelength); + } + while (istream_in.good() && plainlength > 0); + + codelength = encode_end(code); + ostream_in.write(code, codelength); + + base64_init_encodestate(&_state); + + delete [] code; + delete [] plaintext; + } + + void Base64encoder::encode(const char* chars_in, int length_in, std::string& code_out) + { + std::stringstream stream_out; + { + std::stringstream stream_in; + { + stream_in< 0); + + base64_init_decodestate(&_state); + + delete [] code; + delete [] plaintext; + } + + char* Base64decoder::decode(const std::vector& str_in, std::vector& pos_out) + { + std::stringstream stream_out; + { + std::stringstream stream_in; + + pos_out.resize(str_in.size()); + + for (unsigned int i = 0; i < str_in.size(); ++i) + { + stream_in.clear(); + stream_in< #include #include +#include #include #include #include +#include using namespace osgDB; @@ -726,6 +728,61 @@ osg::Image* InputStream::readImage(bool readFromExternal) if ( image && levelSize>0 ) image->setMipmapLevels( levels ); readFromExternal = false; + } else { // ASCII + // _origin, _s & _t & _r, _internalTextureFormat + int origin, s, t, r, internalFormat; + *this >> PROPERTY("Origin") >> origin; + *this >> PROPERTY("Size") >> s >> t >> r; + *this >> PROPERTY("InternalTextureFormat") >> internalFormat; + + // _pixelFormat, _dataType, _packing, _allocationMode + int pixelFormat, dataType, packing, mode; + *this >> PROPERTY("PixelFormat") >> pixelFormat; + *this >> PROPERTY("DataType") >> dataType; + *this >> PROPERTY("Packing") >> packing; + *this >> PROPERTY("AllocationMode") >> mode; + + *this >> PROPERTY("Data"); + unsigned int levelSize = readSize()-1; + *this >> BEGIN_BRACKET; + + // _data + std::vector encodedData; + encodedData.resize(levelSize+1); + readWrappedString(encodedData.at(0)); + + // Read all mipmap levels and to also add them to char* data + // _mipmapData + osg::Image::MipmapDataType levels(levelSize); + for ( unsigned int i=1; i<=levelSize; ++i ) + { + //*this >> levels[i]; + readWrappedString(encodedData.at(i)); + } + + Base64decoder d; + char* data = d.decode(encodedData, levels); + // remove last item as we do not need the actual size + // of the image including all mipmaps + levels.pop_back(); + + *this >> END_BRACKET; + + if ( !data ) + throwException( "InputStream::readImage() Decoding of stream failed. Out of memory." ); + if ( getException() ) return NULL; + + image = new osg::Image; + image->setOrigin( (osg::Image::Origin)origin ); + image->setImage( s, t, r, internalFormat, pixelFormat, dataType, + (unsigned char*)data, (osg::Image::AllocationMode)mode, packing ); + + // Level positions (size of mipmap data) + // from actual size of mipmap data read before + if ( image && levelSize>0 ) + image->setMipmapLevels( levels ); + + readFromExternal = false; } break; case IMAGE_INLINE_FILE: diff --git a/src/osgDB/OutputStream.cpp b/src/osgDB/OutputStream.cpp index 12cfed7b2..993f3c209 100644 --- a/src/osgDB/OutputStream.cpp +++ b/src/osgDB/OutputStream.cpp @@ -12,7 +12,9 @@ */ // Written by Wang Rui, (C) 2010 +#include #include +#include #include #include #include @@ -526,6 +528,31 @@ void OutputStream::writeImage( const osg::Image* img ) if (t<1) t=1; if (r<1) r=1; } + } else { // ASCII + *this << PROPERTY("Origin") << img->getOrigin() << std::endl; // _origin + *this << PROPERTY("Size") << img->s() << img->t() << img->r() << std::endl; // _s & _t & _r + *this << PROPERTY("InternalTextureFormat") << img->getInternalTextureFormat() << std::endl; // _internalTextureFormat + *this << PROPERTY("PixelFormat") << img->getPixelFormat() << std::endl; // _pixelFormat + *this << PROPERTY("DataType") << img->getDataType() << std::endl; // _dataType + *this << PROPERTY("Packing") << img->getPacking() << std::endl; // _packing + *this << PROPERTY("AllocationMode") << img->getAllocationMode() << std::endl; // _allocationMode + + // _data + *this << PROPERTY("Data") << img->getNumMipmapLevels(); + *this << BEGIN_BRACKET << std::endl; + + Base64encoder e; + for(osg::Image::DataIterator img_itr(img); img_itr.valid(); ++img_itr) + { + std::string encodedData; + e.encode((char*)img_itr.data(), img_itr.size(), encodedData); + // Each set of data is written into a separate string so we can + // distiguish between main data and all mipmap levels, so writing + // mipmap size is not required for ASCII mode. + writeWrappedString(encodedData); + } + + *this << END_BRACKET << std::endl; } break; case IMAGE_INLINE_FILE: