From Johannes Scholz, "Attached you find a patch for osgDB::OutputStream and osgDB::InputStream to include osg::Image::data() using Base64 encoding inside the ASCII OSGT, if WriteImageHint=IncludeData is set, only."

git-svn-id: http://svn.openscenegraph.org/osg/OpenSceneGraph/trunk@14748 16af8721-9629-0410-8352-f15c8da7e697
This commit is contained in:
Robert Osfield
2015-03-02 12:11:43 +00:00
parent 1d9e7f144b
commit 58edd10d04
5 changed files with 514 additions and 0 deletions

View File

@@ -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

326
src/osgDB/ConvertBase64.cpp Normal file
View File

@@ -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 <osgDB/ConvertBase64>
#include <sstream>
#include <string.h>
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<<std::string(chars_in, length_in);
}
stream_in.seekg(0, stream_in.beg);
encode(stream_in, stream_out);
}
stream_out.seekg (0, stream_out.beg);
code_out = stream_out.str();
}
int Base64decoder::decode(char value_in)
{
return base64_decode_value(value_in);
}
int Base64decoder::decode(const char* code_in, const int length_in, char* plaintext_out)
{
return base64_decode_block(code_in, length_in, plaintext_out, &_state);
}
void Base64decoder::decode(std::istream& istream_in, std::ostream& ostream_in)
{
base64_init_decodestate(&_state);
const int N = _buffersize;
char* code = new char[N];
char* plaintext = new char[N];
int codelength;
int plainlength;
do
{
istream_in.read((char*)code, N);
codelength = istream_in.gcount();
plainlength = decode(code, codelength, plaintext);
ostream_in.write((const char*)plaintext, plainlength);
}
while (istream_in.good() && codelength > 0);
base64_init_decodestate(&_state);
delete [] code;
delete [] plaintext;
}
char* Base64decoder::decode(const std::vector<std::string>& str_in, std::vector<unsigned int>& 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<<str_in.at(i);
stream_in.seekg(0, stream_in.beg);
decode(stream_in, stream_out);
pos_out.at(i) = stream_out.tellp();
}
}
// Allocate memory for use with osg::Image
char* allocated_out = new char[stream_out.tellp()];
memcpy(allocated_out, stream_out.str().c_str(), stream_out.tellp());
return allocated_out;
}
} // namespace osgDB

View File

@@ -15,9 +15,11 @@
#include <osg/Notify>
#include <osg/ImageSequence>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgDB/XmlParser>
#include <osgDB/FileNameUtils>
#include <osgDB/ObjectWrapper>
#include <osgDB/ConvertBase64>
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<std::string> 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:

View File

@@ -12,7 +12,9 @@
*/
// Written by Wang Rui, (C) 2010
#include <osg/Version>
#include <osg/Notify>
#include <osgDB/ConvertBase64>
#include <osgDB/FileUtils>
#include <osgDB/WriteFile>
#include <osgDB/ObjectWrapper>
@@ -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: