1 /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 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 /* This file is derived from the libb64 project which itself was released to public domain.
15  * For details, see http://sourceforge.net/projects/libb64. Original code by Chris Venter
16  * c++ wrapper for a base64 encoding and decoding algorithm
17 */
18 
19 #include <osgDB/ConvertBase64>
20 
21 #include <sstream>
22 #include <string.h>
23 
24 namespace osgDB
25 {
26 
NullCompressor()27     const int CHARS_PER_LINE = 72;
28 
compress(std::ostream & fout,const std::string & src)29     int base64_decode_value(char value_in)
30     {
31         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};
32         static const char decoding_size = sizeof(decoding);
33         value_in -= 43;
34         if (value_in < 0 || value_in > decoding_size) return -1;
35         return decoding[(int)value_in];
36     }
decompress(std::istream & fin,std::string & target)37 
38     void base64_init_decodestate(base64_decodestate* state_in)
39     {
40         state_in->step = step_a;
41         state_in->plainchar = 0;
42     }
43 
44     int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in)
45     {
46         const char* codechar = code_in;
47         char* plainchar = plaintext_out;
48         char fragment;
49 
50         *plainchar = state_in->plainchar;
51 
52         switch (state_in->step)
53         {
54             while (1)
55             {
56         case step_a:
57                 do {
58                     if (codechar == code_in+length_in)
59                     {
60                         state_in->step = step_a;
ZLibCompressor()61                         state_in->plainchar = *plainchar;
62                         return plainchar - plaintext_out;
compress(std::ostream & fout,const std::string & src)63                     }
64                     fragment = (char)base64_decode_value(*codechar++);
65                 } while (fragment < 0);
66                 *plainchar    = (fragment & 0x03f) << 2;
67         case step_b:
68                 do {
69                     if (codechar == code_in+length_in)
70                     {
71                         state_in->step = step_b;
72                         state_in->plainchar = *plainchar;
73                         return plainchar - plaintext_out;
74                     }
75                     fragment = (char)base64_decode_value(*codechar++);
76                 } while (fragment < 0);
77                 *plainchar++ |= (fragment & 0x030) >> 4;
78                 *plainchar    = (fragment & 0x00f) << 4;
79         case step_c:
80                 do {
81                     if (codechar == code_in+length_in)
82                     {
83                         state_in->step = step_c;
84                         state_in->plainchar = *plainchar;
85                         return plainchar - plaintext_out;
86                     }
87                     fragment = (char)base64_decode_value(*codechar++);
88                 } while (fragment < 0);
89                 *plainchar++ |= (fragment & 0x03c) >> 2;
90                 *plainchar    = (fragment & 0x003) << 6;
91         case step_d:
92                 do {
93                     if (codechar == code_in+length_in)
94                     {
95                         state_in->step = step_d;
96                         state_in->plainchar = *plainchar;
97                         return plainchar - plaintext_out;
98                     }
99                     fragment = (char)base64_decode_value(*codechar++);
100                 } while (fragment < 0);
101                 *plainchar++   |= (fragment & 0x03f);
102             }
103         }
104         /* control should not reach here */
105         return plainchar - plaintext_out;
106     }
107 
108     void base64_init_encodestate(base64_encodestate* state_in)
109     {
110         state_in->step = step_A;
111         state_in->result = 0;
112         state_in->stepcount = 0;
113     }
114 
decompress(std::istream & fin,std::string & target)115     char base64_encode_value(char value_in)
116     {
117         static const char* encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
118         if (value_in > 63) return '=';
119         return encoding[(int)value_in];
120     }
121 
122     int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in)
123     {
124         const char* plainchar = plaintext_in;
125         const char* const plaintextend = plaintext_in + length_in;
126         char* codechar = code_out;
127         char result;
128         char fragment;
129 
130         result = state_in->result;
131 
132         switch (state_in->step)
133         {
134             while (1)
135             {
136         case step_A:
137                 if (plainchar == plaintextend)
138                 {
139                     state_in->result = result;
140                     state_in->step = step_A;
141                     return codechar - code_out;
142                 }
143                 fragment = *plainchar++;
144                 result = (fragment & 0x0fc) >> 2;
145                 *codechar++ = base64_encode_value(result);
146                 result = (fragment & 0x003) << 4;
147         case step_B:
148                 if (plainchar == plaintextend)
149                 {
150                     state_in->result = result;
151                     state_in->step = step_B;
152                     return codechar - code_out;
153                 }
154                 fragment = *plainchar++;
155                 result |= (fragment & 0x0f0) >> 4;
156                 *codechar++ = base64_encode_value(result);
157                 result = (fragment & 0x00f) << 2;
158         case step_C:
159                 if (plainchar == plaintextend)
160                 {
161                     state_in->result = result;
162                     state_in->step = step_C;
163                     return codechar - code_out;
164                 }
165                 fragment = *plainchar++;
166                 result |= (fragment & 0x0c0) >> 6;
167                 *codechar++ = base64_encode_value(result);
168                 result  = (fragment & 0x03f) >> 0;
169                 *codechar++ = base64_encode_value(result);
170 
171                 ++(state_in->stepcount);
172                 if (state_in->stepcount == CHARS_PER_LINE/4)
173                 {
174                     *codechar++ = '\n';
175                     state_in->stepcount = 0;
176                 }
177             }
178         }
179         /* control should not reach here */
180         return codechar - code_out;
181     }
182 
183     int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
184     {
185         char* codechar = code_out;
186 
187         switch (state_in->step)
188         {
189         case step_B:
190             *codechar++ = base64_encode_value(state_in->result);
191             *codechar++ = '=';
192             *codechar++ = '=';
193             break;
194         case step_C:
195             *codechar++ = base64_encode_value(state_in->result);
196             *codechar++ = '=';
197             break;
198         case step_A:
199             break;
200         }
201         *codechar++ = '\n';
202 
203         return codechar - code_out;
204     }
205 
206     int Base64encoder::encode(char value_in)
207     {
208         return base64_encode_value(value_in);
209     }
210 
211     int Base64encoder::encode(const char* code_in, const int length_in, char* plaintext_out)
212     {
213         return base64_encode_block(code_in, length_in, plaintext_out, &_state);
214     }
215 
216     int Base64encoder::encode_end(char* plaintext_out)
217     {
218         return base64_encode_blockend(plaintext_out, &_state);
219     }
220 
221     void Base64encoder::encode(std::istream& istream_in, std::ostream& ostream_in)
222     {
223         base64_init_encodestate(&_state);
224 
225         const int N = _buffersize;
226         char* plaintext = new char[N];
227         char* code = new char[2*N];
228         int plainlength;
229         int codelength;
230 
231         do
232         {
233             istream_in.read(plaintext, N);
234             plainlength = istream_in.gcount();
235 
236             codelength = encode(plaintext, plainlength, code);
237             ostream_in.write(code, codelength);
238         }
239         while (istream_in.good() && plainlength > 0);
240 
241         codelength = encode_end(code);
242         ostream_in.write(code, codelength);
243 
244         base64_init_encodestate(&_state);
245 
246         delete [] code;
247         delete [] plaintext;
248     }
249 
250     void Base64encoder::encode(const char* chars_in, int length_in, std::string& code_out)
251     {
252         std::stringstream stream_out;
253         {
254             std::stringstream stream_in;
255             {
256                 stream_in<<std::string(chars_in, length_in);
257             }
258             stream_in.seekg(0, stream_in.beg);
259             encode(stream_in, stream_out);
260         }
261         stream_out.seekg (0, stream_out.beg);
262         code_out = stream_out.str();
263     }
264 
265     int Base64decoder::decode(char value_in)
266     {
267         return base64_decode_value(value_in);
268     }
269 
270     int Base64decoder::decode(const char* code_in, const int length_in, char* plaintext_out)
271     {
272         return base64_decode_block(code_in, length_in, plaintext_out, &_state);
273     }
274 
275     void Base64decoder::decode(std::istream& istream_in, std::ostream& ostream_in)
276     {
277         base64_init_decodestate(&_state);
278 
279         const int N = _buffersize;
280         char* code = new char[N];
281         char* plaintext = new char[N];
282         int codelength;
283         int plainlength;
284 
285         do
286         {
287             istream_in.read((char*)code, N);
288             codelength = istream_in.gcount();
289             plainlength = decode(code, codelength, plaintext);
290             ostream_in.write((const char*)plaintext, plainlength);
291         }
292         while (istream_in.good() && codelength > 0);
293 
294         base64_init_decodestate(&_state);
295 
296         delete [] code;
297         delete [] plaintext;
298     }
299 
300     char* Base64decoder::decode(const std::vector<std::string>& str_in, std::vector<unsigned int>& pos_out)
301     {
302         std::stringstream stream_out;
303         {
304             std::stringstream stream_in;
305 
306             pos_out.resize(str_in.size());
307 
308             for (unsigned int i = 0; i < str_in.size(); ++i)
309             {
310                 stream_in.clear();
311                 stream_in<<str_in.at(i);
312                 stream_in.seekg(0, stream_in.beg);
313 
314                 decode(stream_in, stream_out);
315                 pos_out.at(i) = stream_out.tellp();
316             }
317         }
318 
319         // Allocate memory for use with osg::Image
320         const std::string str = stream_out.str();
321         char* allocated_out = new char[str.size()];
322         memcpy(allocated_out, str.c_str(), str.size());
323 
324         return allocated_out;
325     }
326 
327 } // namespace osgDB
328