See what's going on with flipcode!




This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

 

  Base64 Encoder / Decoder
  Submitted by



If you've never heard of it, base64 is a standard for storing binary data in a 7-bit clean format. It's commonly used where only text is appropriate but binary files are desired, such as email and usenet. I know it is a bit of a stretch to call this game-related, so here's my story. I've been using TinyXML for data storage in my game project, and I wanted to move some binary data into the XML files. The only problem is that TinyXML does not and will not support CDATA sections, which is XML's binary storage method. Base64 fits the need nicely, and I decided to implement it myself just for kicks. The result is this piece of work -- short and sweet. The two functions, base64::encode and base64::decode, operate very similarly to std::copy. Using the STL's iterator library, you can easily encode and decode to and from straight buffers, containers, or files via streams. The functions take as parameters an input iterator range and an output iterator, and just as std::copy you can throw anything at it, from raw pointers to container iterators to istream_ and ostream_iterators. Here's some example usage:
#include <iostream
#include <fstream
#include <iterator
#include <vector
#include <cstdlib
#include <cstring

#include "base64.hpp"

using namespace std;

int main() { const int size = 439; char source[size], source2[size]; vector<char dest; int i;

// initialize for(i=0; i < size; ++i) source[i] = (rand() & 0xFF);

// convert to base64 base64::encode((char*)source, source+size, back_inserter(dest));

// spit out the result copy(dest.begin(), dest.end(), ostream_iterator<char(cout)); cout << endl;

// convert back to binary base64::decode(dest.begin(), dest.end(), source2);

// make sure we got the same thing if (memcmp(source, source2, size) == 0) cout <<"They're the same!" << endl; else cout << "They're different!" << endl;

// encode from memory to a file { ofstream file("b64.txt"); base64::encode((char*)source, source+size, ostream_iterator<char(file)); }

// decode from file to file { ifstream in("b64.txt"); ofstream out("b64.bin", ios::binary);

base64::decode(istream_iterator<char(in), istream_iterator<char(), ostream_iterator<char(out)

}

return 0; }

I'm releasing it under the zlib license -- basically, do whatever you want with it, just don't blame me for the results. :) Comments and feedback are welcome. I had fun writing it, and if it's instructive or useful to anyone else, all the better. Ryan Petrie (aka hurri)

Currently browsing [base64.zip] (5,598 bytes) - [base64.hpp] - (4,702 bytes)

/* base64.hpp - base64 encoder/decoder implementing section 6.8 of RFC2045

Copyright (C) 2002 Ryan Petrie (ryanpetrie@netscape.net) and released under the zlib license:

This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.

Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:

1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution.

--------------------------------------------------------------------------

base64::encoder and base64::decoder are intended to be identical in usage as the STL's std::copy and similar algorithms. They require as parameters an input iterator range and an output iterator, and just as std::copy, the iterators can be bare pointers, container iterators, or even adaptors such as ostream_iterator.

Examples:

// encode/decode with in-place memory buffers char source[size], dest[size*2]; base64::encode(source, source+size, dest); base64::decode(dest, dest+size*2, source);

// encode from memory to a file char source[size]; ofstream file("output.txt"); base64::encode((char*)source, source+size, ostream_iterator<char>(file));

// decode from file to a standard container ifstream file("input.txt"); vector<char> dest; base64::decode(istream_iterator<char>(file), istream_iterator<char>(), back_inserter(dest) ); */


#ifndef _BASE64_HPP #define _BASE64_HPP

#include <algorithm>

namespace base64 { typedef unsigned uint32; typedef unsigned char uint8;

extern const char* to_table; extern const char* to_table_end;

extern const char* from_table;

template <class InputIterator, class OutputIterator> void encode(const InputIterator& begin, const InputIterator& end, OutputIterator out) { InputIterator it = begin; int lineSize = 0; int bytes; do { uint32 input = 0;

// get the next three bytes into "in" (and count how many we actually get) bytes = 0; for(; (bytes < 3) && (it != end); ++bytes, ++it) { input <<= 8; input += static_cast<uint8>(*it); }

// convert to base64 int bits = bytes*8; while (bits > 0) { bits -= 6; const uint8 index = ((bits < 0) ? input << -bits : input >> bits) & 0x3F; *out = to_table[index]; ++out; ++lineSize; }

if (lineSize >= 76) // ensure proper line length { *out = 13; ++out; *out = 10; ++out; lineSize = 0; }

} while (bytes == 3);

// add pad characters if necessary if (bytes > 0) for(int i=bytes; i < 3; ++i) { *out = '='; ++out; } }

template <class InputIterator, class OutputIterator> void decode(const InputIterator& begin, const InputIterator& end, OutputIterator out) { InputIterator it = begin; int chars;

do { uint8 input[4] = {0, 0, 0, 0};

// get four characters chars=0; while((chars<4) && (it != end)) { uint8 c = static_cast<char>(*it); if (c == '=') break; // pad character marks the end of the stream ++it;

if (std::find(to_table, to_table_end, c) != to_table_end) { input[chars] = from_table[c]; chars++; } }

// output the binary data if (chars >= 2) { *out = static_cast<uint8>((input[0] << 2) + (input[1] >> 4)); ++out; if (chars >= 3) { *out = static_cast<uint8>((input[1] << 4) + (input[2] >> 2)); ++out; if (chars >= 4) { *out = static_cast<uint8>((input[2] << 6) + input[3]); ++out; } } } } while (chars == 4);

}

} // end namespace #endif

Currently browsing [base64.zip] (5,598 bytes) - [test.cpp] - (1,257 bytes)

#include <iostream>
#include <fstream>
#include <iterator>
#include <vector>
#include <cstdlib>
#include <cstring>

#include "base64.hpp"

using namespace std;

int main() { const int size = 439; char source[size], source2[size]; vector<char> dest; int i;

// initialize for(i=0; i < size; ++i) source[i] = (rand() & 0xFF);

// convert to base64 base64::encode((char*)source, source+size, back_inserter(dest));

// spit out the result copy(dest.begin(), dest.end(), ostream_iterator<char>(cout)); cout << endl;

// convert back to binary base64::decode(dest.begin(), dest.end(), source2);

// make sure we got the same thing if (memcmp(source, source2, size) == 0) cout <<"They're the same!" << endl; else cout << "They're different!" << endl;

// encode from memory to a file { ofstream file("b64.txt"); base64::encode((char*)source, source+size, ostream_iterator<char>(file)); }

// decode from file to file { ifstream in("b64.txt"); ofstream out("b64.bin", ios::binary);

base64::decode(istream_iterator<char>(in), istream_iterator<char>(), ostream_iterator<char>(out) ); } return 0; }

Currently browsing [base64.zip] (5,598 bytes) - [base64.cpp] - (1,312 bytes)

namespace base64
{
  const char _to_table[64] =
  { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
    'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
    'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
    'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
    'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
    'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
    'w', 'x', 'y', 'z', '0', '1', '2', '3',
    '4', '5', '6', '7', '8', '9', '+', '/'
  };
  const char* to_table = _to_table;

const char* to_table_end = _to_table + sizeof(_to_table);

const char _from_table[128] = { -1, -1, -1, -1, -1, -1, -1, -1, // 0 -1, -1, -1, -1, -1, -1, -1, -1, // 8 -1, -1, -1, -1, -1, -1, -1, -1, // 16 -1, -1, -1, -1, -1, -1, -1, -1, // 24 -1, -1, -1, -1, -1, -1, -1, -1, // 32 -1, -1, -1, 62, -1, -1, -1, 63, // 40 52, 53, 54, 55, 56, 57, 58, 59, // 48 60, 61, -1, -1, -1, 0, -1, -1, // 56 -1, 0, 1, 2, 3, 4, 5, 6, // 64 7, 8, 9, 10, 11, 12, 13, 14, // 72 15, 16, 17, 18, 19, 20, 21, 22, // 80 23, 24, 25, -1, -1, -1, -1, -1, // 88 -1, 26, 27, 28, 29, 30, 31, 32, // 96 33, 34, 35, 36, 37, 38, 39, 40, // 104 41, 42, 43, 44, 45, 46, 47, 48, // 112 49, 50, 51, -1, -1, -1, -1, -1 // 120 }; const char* from_table = _from_table; }




The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.

 

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.