1 /////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2009-2014 Alan Wright. All rights reserved.
3 // Distributable under the terms of either the Apache License (Version 2.0)
4 // or the GNU Lesser General Public License.
5 /////////////////////////////////////////////////////////////////////////////
6 
7 #include "LuceneInc.h"
8 #include "Base64.h"
9 #include "MiscUtils.h"
10 #include "UnicodeUtils.h"
11 
12 namespace Lucene {
13 
14 const String Base64::BASE64_CHARS = L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
15 
~Base64()16 Base64::~Base64() {
17 }
18 
encode(ByteArray bytes)19 String Base64::encode(ByteArray bytes) {
20     return encode(bytes.get(), bytes.size());
21 }
22 
encode(const uint8_t * bytes,int32_t length)23 String Base64::encode(const uint8_t* bytes, int32_t length) {
24     String result;
25     uint8_t byteArray3[3];
26     uint8_t byteArray4[4];
27     int32_t i = 0;
28 
29     while (length--) {
30         byteArray3[i++] = *(bytes++);
31         if (i == 3) {
32             byteArray4[0] = (byteArray3[0] & 0xfc) >> 2;
33             byteArray4[1] = ((byteArray3[0] & 0x03) << 4) + ((byteArray3[1] & 0xf0) >> 4);
34             byteArray4[2] = ((byteArray3[1] & 0x0f) << 2) + ((byteArray3[2] & 0xc0) >> 6);
35             byteArray4[3] = byteArray3[2] & 0x3f;
36 
37             for (i = 0; i < 4; ++i) {
38                 result += BASE64_CHARS[byteArray4[i]];
39             }
40             i = 0;
41         }
42     }
43 
44     if (i != 0) {
45         for (int32_t j = i; j < 3; ++j) {
46             byteArray3[j] = 0;
47         }
48 
49         byteArray4[0] = (byteArray3[0] & 0xfc) >> 2;
50         byteArray4[1] = ((byteArray3[0] & 0x03) << 4) + ((byteArray3[1] & 0xf0) >> 4);
51         byteArray4[2] = ((byteArray3[1] & 0x0f) << 2) + ((byteArray3[2] & 0xc0) >> 6);
52         byteArray4[3] = byteArray3[2] & 0x3f;
53 
54         for (int32_t j = 0; j < i + 1; ++j) {
55             result += BASE64_CHARS[byteArray4[j]];
56         }
57 
58         while (i++ < 3) {
59             result += L'=';
60         }
61     }
62     return result;
63 }
64 
decode(const String & str)65 ByteArray Base64::decode(const String& str) {
66     int32_t length = str.length();
67     uint8_t byteArray4[4];
68     uint8_t byteArray3[3];
69 
70     int32_t i = 0;
71     int32_t charIndex = 0;
72 
73     ByteArray result(ByteArray::newInstance(length / 2));
74     int32_t resultIndex = 0;
75 
76     while (length-- && str[charIndex] != L'=' && isBase64(str[charIndex])) {
77         byteArray4[i++] = (uint8_t)str[charIndex++];
78         if (i == 4) {
79             for (i = 0; i < 4; ++i) {
80                 byteArray4[i] = static_cast<uint8_t>(BASE64_CHARS.find(byteArray4[i]));
81             }
82             byteArray3[0] = (byteArray4[0] << 2) + ((byteArray4[1] & 0x30) >> 4);
83             byteArray3[1] = ((byteArray4[1] & 0xf) << 4) + ((byteArray4[2] & 0x3c) >> 2);
84             byteArray3[2] = ((byteArray4[2] & 0x3) << 6) + byteArray4[3];
85 
86             for (i = 0; i < 3; ++i) {
87                 if (resultIndex >= result.size()) {
88                     result.resize((int32_t)((double)result.size() * 1.5));
89                 }
90                 result[resultIndex++] = byteArray3[i];
91             }
92 
93             i = 0;
94         }
95     }
96 
97     if (i != 0) {
98         for (int32_t j = i; j < 4; ++j) {
99             byteArray4[j] = 0;
100         }
101         for (int32_t j = 0; j < 4; ++j) {
102             byteArray4[j] = static_cast<uint8_t>(BASE64_CHARS.find(byteArray4[j]));
103         }
104         byteArray3[0] = (byteArray4[0] << 2) + ((byteArray4[1] & 0x30) >> 4);
105         byteArray3[1] = ((byteArray4[1] & 0xf) << 4) + ((byteArray4[2] & 0x3c) >> 2);
106         byteArray3[2] = ((byteArray4[2] & 0x3) << 6) + byteArray4[3];
107 
108         for (int32_t j = 0; j < i - 1; ++j) {
109             if (resultIndex >= result.size()) {
110                 result.resize((int32_t)((double)result.size() * 1.5));
111             }
112             result[resultIndex++] = byteArray3[j];
113         }
114     }
115 
116     result.resize(resultIndex);
117 
118     return result;
119 }
120 
isBase64(wchar_t ch)121 bool Base64::isBase64(wchar_t ch) {
122     return (UnicodeUtil::isAlnum(ch) || ch == L'+' || ch == L'/');
123 }
124 
125 }
126