OZ++ Class: Base64Decoder
/******************************************************************************
 *
 * Copyright (c) 2014 Antillia.com TOSHIYUKI ARAI. ALL RIGHTS RESERVED.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions, and the following disclaimer.
 *  
 * 2. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *
 *  Base64Decoder.h
 *
 *****************************************************************************/

#pragma once

#include <oz++/CommonObject.h>
#include <oz++/Bytes.h>
#include <oz++/CharString.h>

/**
 * Base64Decoder class reprents a base64decoder.
 */
namespace OZ {

class Base64Decoder :public CommonObject {

public:
  /**
   */
  Base64Decoder() {

  }


  /**
   */
  ~Base64Decoder() {

  }

public:
  /**
   * Decode base64encoded string.
   * @param string  [in] NULL terminated string of Base64Encoded data.
   * @param bytes    [out] Reference to Bytes to return decoded data.
   */
  int decode(const CharString& string, Bytes& bytes) {
    return decode((const char*)string, bytes);
  }

public:
  /**
   * Decode base64encoded string.
   * @param string  [in] NULL terminated string of Base64Encoded data.
   * @param bytes    [out] Reference to Bytes to return decoded data.
   */
  int decode(const char* string, Bytes& bytes) {
    unsigned char* outBytes = NULL;
    int outLen =0;
    int rc = 0;
    if (string == NULL) {
      return rc;
    }

    rc = decode(string, strlen(string), &outBytes, &outLen);
    if (rc>0) {
      bytes.shallowCopy(outBytes, outLen);
    }
    
    return rc;  
  }

public:

  /**
   * Decode base64encoded data.
   * @param data    [in] NULL terminated string of Base64Encoded data.
   * @param len    [in] Byte length of data.
   * @param outBytes  [out] Pointer to pointer for unsigned char* to return decoded data.
   * @param outLen  [out] Pointer to int to return the lenghth of decoded dta. 
   */
  int decode(const char* data, 
       int len,
      unsigned char** outBytes,
      int* outLen) {

    static const char table[] ={
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x3F,
      0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,
      0x3C, 0x3D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
      0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
      0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
      0x17, 0x18, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
      0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
      0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
      0x31, 0x32, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00};

    if (data == NULL || len == 0) {
      return 0;
    }
    if (outBytes == NULL || outLen ==NULL) {
      return 0;
    }

    const char PADDING = '=';

    // Compute a length of padding.
    int pad = 0;
    for (int s = len - 1; s >=0; s--) {
      if (data[s] == PADDING) {
        pad++;
      }
    }

    // Allocating a memory for decoded area.
    int length = len * 3 / 4 - pad;

    unsigned char* out = new unsigned char[length];        
    memset(out, 0, length);

    int n = 0;
    //Convert 4 bytes to 3 bytes.
    for (int i = 0; i <len; i += 4) {
      int block = (table[(int)data[i]] << 18)
          + (table[(int)data[i + 1]] << 12)
          + (table[(int)data[i + 2]] << 6)
          + (table[(int)data[i + 3]]);

      for (int j = 0; j < 3 && n + j < length; j++) {
        //printf("%d...\n", n+j);
        out[n + j] = ((block >> (8 * (2 - j))) & 0xff);
      }
      n += 3;
    }

    *outBytes = out;
    *outLen   = length;

    return length;
  }
};

}