2005/5/9

     
 

Base64.cpp

artefaktur
// -*- mode:C++; tab-width:2; c-basic-offset:2; indent-tabs-mode:nil -*- 
//
// Copyright (C) 2000-2005 by Roger Rene Kommer / artefaktur, Kassel, Germany.
// 
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public License (LGPL).
// 
// 
// 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 
// License ACDK-FreeLicense document enclosed in the distribution
// for more for more details.
// This file is part of the Artefaktur Component Development Kit:
//                         ACDK
// 
// Please refer to
// - http://www.acdk.de
// - http://www.artefaktur.com
// - http://acdk.sourceforge.net
// for more information.
// 
// $Header: /cvsroot/acdk/acdk/acdk_text/src/acdk/text/Base64.cpp,v 1.10 2005/04/08 10:53:21 kommer Exp $


#include "Base64.h"
#include <acdk/lang/Byte.h>

namespace acdk {
namespace text {

namespace {
/** @internal */
  char valid_chars[] = 
  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

/** @internal */
void
_decode(byte* decodeMap, //128
        byte* tempbuf, 
        byteArray& retbuffer, int& written)
{
  int towrite = 3;
  if (tempbuf[3] == '=')  
    towrite = 2;
  if (tempbuf[2] == '=')  
    towrite = 1;
  int b0 = decodeMap[tempbuf[0]];
  int b1 = decodeMap[tempbuf[1]];
  int b2 = decodeMap[tempbuf[2]];
  int b3 = decodeMap[tempbuf[3]];
  switch (towrite) {
  case 1:
    retbuffer[written++] = (byte)(b0 << 2 & 0xfc | b1 >> 4 & 0x3);
    break;
  case 2:
    retbuffer[written++] = (byte)(b0 << 2 & 0xfc | b1 >> 4 & 0x3);
    retbuffer[written++] = (byte)(b1 << 4 & 0xf0 | b2 >> 2 & 0xf);
    return;
  case 3:
    retbuffer[written++] = (byte)(b0 << 2 & 0xfc | b1 >> 4 & 0x3);
    retbuffer[written++] = (byte)(b1 << 4 & 0xf0 | b2 >> 2 & 0xf);
    retbuffer[written++] = (byte)(b2 << 6 & 0xc0 | b3 & 0x3f);
  default:
    THROW1(RuntimeException, "Unexpected Stream format in Base64");
  }
}


} // annon namespace
//static 
RbyteArray 
Base64::encode(IN(RbyteArray) in)
{
  if (in == Nil)
    return Nil;
  int len = in->length();
  if (len <= 0)  
    return new byteArray(0);
  
  RbyteArray out = new byteArray(len / 3 * 4 + 4);
  int rindex = 0;
  int cidx = 0;
  int rest = len;
  while (rest >= 3) {
    int i = ((in[rindex] & 0xff) << 16) 
            + ((in[rindex + 1] & 0xff) << 8)
            + (in[rindex+2] & 0xff);
    out[cidx++] = valid_chars[i >> 18];
    out[cidx++] = valid_chars[(i >> 12) & 0x3f];
    out[cidx++] = valid_chars[(i >> 6) & 0x3f];
    out[cidx++] = valid_chars[i & 0x3f];
    rindex += 3;
    rest -= 3;
  }
  if (rest == 1) {
    int i = in[rindex] & 0xff;
    out[cidx++] = valid_chars[i>>2];
    out[cidx++] = valid_chars[(i<<4)&0x3f];
    out[cidx++] = '=';
    out[cidx++] = '=';
  } else if (rest == 2) {
    int i = ((in[rindex]&0xff)<<8)+(in[rindex+1]&0xff);
    out[cidx++] = valid_chars[i>>10];
    out[cidx++] = valid_chars[(i>>4)&0x3f];
    out[cidx++] = valid_chars[(i<<2)&0x3f];
    out[cidx++] = '=';
  }
  out->resize(cidx);
  return out;
}


  
//static 
RbyteArray 
Base64::decode(IN(RbyteArray) data)
{
  if (data == Nil)  
    return Nil;
  int len = data->length();
  if (len == 0)
    return new byteArray(0);

  byte decodeMap[128];
  int i;
	for (i = 0; i < 128; i++)
	  decodeMap[int(valid_chars[i])] = (byte)i;
  
  byte tempbuf[4];

  
  int tempbufpos = 0;
  RbyteArray retbuffer = new byteArray(len / 4 * 3 + 3);
  int written = 0;
  for (i = 0; i < len; i ++) 
  {
    byte ch = data[i];
    if (ch == '=' || (ch < 64 && decodeMap[ch] != acdk::lang::Byte::MAX_VALUE))
    {
      tempbuf[tempbufpos++] = ch;
      if (tempbufpos == 4) {
        tempbufpos = 0;
        _decode(decodeMap, tempbuf, *retbuffer, written);
      }
    }
  }
  retbuffer->resize(written);
  return retbuffer;
}


} // text
} // acdk