// @(#)root/base:$Id$
// Author: Gerardo Ganis + Fons Rademakers   15/5/2009

/*************************************************************************
 * Copyright (C) 1995-2009, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TBase64                                                              //
//                                                                      //
// This code implements the Base64 encoding and decoding.               //
// Base64 encoded messages are typically used in authentication         //
// protocols and to pack binary data in HTTP messages.                  //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TBase64.h"

ClassImp(TBase64)


//_________________________________________________________________________
static int ToB64low(const char *in, char *out, int mod)
{
   // Base64 encoding of 3 bytes from in.
   // Output (4 bytes) saved in out (not null terminated).
   // Returns 0 on success, -1 if input or output arrays are
   // not defined.

   static char b64ref[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',
      '+','/'
   };

   if (!in || !out)
      return -1;

   if (mod == 1) {
      *out++ = b64ref[ 0x3F & (in[0] >> 2) ];
      *out++ = b64ref[ 0x3F & (0x30 & (in[0] << 4)) ];
      *out++ = '=';
      *out++ = '=';
   } else if (mod == 2) {
      *out++ = b64ref[ 0x3F & (in[0] >> 2) ];
      *out++ = b64ref[ 0x3F & ((0x30 & (in[0] << 4)) | (0x0F & (in[1] >> 4))) ];
      *out++ = b64ref[ 0x3F & (0x3C & (in[1] << 2)) ];
      *out++ = '=';
   } else {
      *out++ = b64ref[ (int)(0x3F & (in[0] >> 2)) ];
      *out++ = b64ref[ 0x3F & ((0x30 & (in[0] << 4)) | (0x0F & (in[1] >> 4))) ];
      *out++ = b64ref[ 0x3F & ((0x3C & (in[1] << 2)) | (0x03 & (in[2] >> 6))) ];
      *out++ = b64ref[ 0x3F & in[2] ];
   }

   return 0;
}

//_________________________________________________________________________
static int FromB64low(const char *in, TString &out)
{
   // Base64 decoding of 4 bytes from in.
   // Output (3 bytes) returned in out.
   // No check for base64-ness of input characters.

   static int b64inv[256] = {
      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,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,-1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
      -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
   };

   UInt_t i0 = (UInt_t)(in[0]);
   UInt_t i1 = (UInt_t)(in[1]);
   UInt_t i2 = (UInt_t)(in[2]);
   UInt_t i3 = (UInt_t)(in[3]);
   if (in[3] != '=') {
      out.Append((char)(0xFC & (b64inv[i0] << 2)) | (0x03 & (b64inv[i1] >> 4)));
      out.Append((char)(0xF0 & (b64inv[i1] << 4)) | (0x0F & (b64inv[i2] >> 2)));
      out.Append((char)(0xC0 & (b64inv[i2] << 6)) | (0x3F &  b64inv[i3]));
      return 3;
   } else if (in[2] == '=') {
      out.Append((char)(0xFC & (b64inv[i0] << 2)) | (0x03 & (b64inv[i1] >> 4)));
      return 1;
   } else {
      out.Append((char)(0xFC & (b64inv[i0] << 2)) | (0x03 & (b64inv[i1] >> 4)));
      out.Append((char)(0xF0 & (b64inv[i1] << 4)) | (0x0F & (b64inv[i2] >> 2)));
      return 2;
   }
}

//______________________________________________________________________________
TString TBase64::Encode(const char *data)
{
   // Transform data into a null terminated base64 string.

   return Encode(data, strlen(data));
}

//______________________________________________________________________________
TString TBase64::Encode(const char *data, Int_t len)
{
   // Transform len bytes from data into a null terminated base64 string.

   TString ret(len * 2);

   int mod = 0;
   char oo[5] = {0};
   for (int i = 0; i < len; i += 3) {
      mod = len-i;
      ToB64low(data+i, oo, mod);
      oo[4] = 0;
      ret += oo;
   }
   return ret;
}

//______________________________________________________________________________
TString TBase64::Decode(const char *data)
{
   // Decode a base64 string date into a generic TString.
   // No check for base64-ness of input characters.

   int len = strlen(data);
   TString ret(len);

   for (int i = 0; i < len; i += 4)
      FromB64low(data+i, ret);

   return ret;
}
 TBase64.cxx:1
 TBase64.cxx:2
 TBase64.cxx:3
 TBase64.cxx:4
 TBase64.cxx:5
 TBase64.cxx:6
 TBase64.cxx:7
 TBase64.cxx:8
 TBase64.cxx:9
 TBase64.cxx:10
 TBase64.cxx:11
 TBase64.cxx:12
 TBase64.cxx:13
 TBase64.cxx:14
 TBase64.cxx:15
 TBase64.cxx:16
 TBase64.cxx:17
 TBase64.cxx:18
 TBase64.cxx:19
 TBase64.cxx:20
 TBase64.cxx:21
 TBase64.cxx:22
 TBase64.cxx:23
 TBase64.cxx:24
 TBase64.cxx:25
 TBase64.cxx:26
 TBase64.cxx:27
 TBase64.cxx:28
 TBase64.cxx:29
 TBase64.cxx:30
 TBase64.cxx:31
 TBase64.cxx:32
 TBase64.cxx:33
 TBase64.cxx:34
 TBase64.cxx:35
 TBase64.cxx:36
 TBase64.cxx:37
 TBase64.cxx:38
 TBase64.cxx:39
 TBase64.cxx:40
 TBase64.cxx:41
 TBase64.cxx:42
 TBase64.cxx:43
 TBase64.cxx:44
 TBase64.cxx:45
 TBase64.cxx:46
 TBase64.cxx:47
 TBase64.cxx:48
 TBase64.cxx:49
 TBase64.cxx:50
 TBase64.cxx:51
 TBase64.cxx:52
 TBase64.cxx:53
 TBase64.cxx:54
 TBase64.cxx:55
 TBase64.cxx:56
 TBase64.cxx:57
 TBase64.cxx:58
 TBase64.cxx:59
 TBase64.cxx:60
 TBase64.cxx:61
 TBase64.cxx:62
 TBase64.cxx:63
 TBase64.cxx:64
 TBase64.cxx:65
 TBase64.cxx:66
 TBase64.cxx:67
 TBase64.cxx:68
 TBase64.cxx:69
 TBase64.cxx:70
 TBase64.cxx:71
 TBase64.cxx:72
 TBase64.cxx:73
 TBase64.cxx:74
 TBase64.cxx:75
 TBase64.cxx:76
 TBase64.cxx:77
 TBase64.cxx:78
 TBase64.cxx:79
 TBase64.cxx:80
 TBase64.cxx:81
 TBase64.cxx:82
 TBase64.cxx:83
 TBase64.cxx:84
 TBase64.cxx:85
 TBase64.cxx:86
 TBase64.cxx:87
 TBase64.cxx:88
 TBase64.cxx:89
 TBase64.cxx:90
 TBase64.cxx:91
 TBase64.cxx:92
 TBase64.cxx:93
 TBase64.cxx:94
 TBase64.cxx:95
 TBase64.cxx:96
 TBase64.cxx:97
 TBase64.cxx:98
 TBase64.cxx:99
 TBase64.cxx:100
 TBase64.cxx:101
 TBase64.cxx:102
 TBase64.cxx:103
 TBase64.cxx:104
 TBase64.cxx:105
 TBase64.cxx:106
 TBase64.cxx:107
 TBase64.cxx:108
 TBase64.cxx:109
 TBase64.cxx:110
 TBase64.cxx:111
 TBase64.cxx:112
 TBase64.cxx:113
 TBase64.cxx:114
 TBase64.cxx:115
 TBase64.cxx:116
 TBase64.cxx:117
 TBase64.cxx:118
 TBase64.cxx:119
 TBase64.cxx:120
 TBase64.cxx:121
 TBase64.cxx:122
 TBase64.cxx:123
 TBase64.cxx:124
 TBase64.cxx:125
 TBase64.cxx:126
 TBase64.cxx:127
 TBase64.cxx:128
 TBase64.cxx:129
 TBase64.cxx:130
 TBase64.cxx:131
 TBase64.cxx:132
 TBase64.cxx:133
 TBase64.cxx:134
 TBase64.cxx:135
 TBase64.cxx:136
 TBase64.cxx:137
 TBase64.cxx:138
 TBase64.cxx:139
 TBase64.cxx:140
 TBase64.cxx:141
 TBase64.cxx:142
 TBase64.cxx:143
 TBase64.cxx:144
 TBase64.cxx:145
 TBase64.cxx:146
 TBase64.cxx:147
 TBase64.cxx:148
 TBase64.cxx:149
 TBase64.cxx:150
 TBase64.cxx:151
 TBase64.cxx:152
 TBase64.cxx:153