1 | /* |
---|---|
2 | * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"). |
5 | * You may not use this file except in compliance with the License. |
6 | * A copy of the License is located at |
7 | * |
8 | * http://aws.amazon.com/apache2.0 |
9 | * |
10 | * or in the "license" file accompanying this file. This file is distributed |
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either |
12 | * express or implied. See the License for the specific language governing |
13 | * permissions and limitations under the License. |
14 | */ |
15 | |
16 | #include <aws/core/utils/base64/Base64.h> |
17 | #include <cstring> |
18 | |
19 | using namespace Aws::Utils::Base64; |
20 | |
21 | static const uint8_t SENTINEL_VALUE = 255; |
22 | static const char BASE64_ENCODING_TABLE_MIME[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
23 | |
24 | namespace Aws |
25 | { |
26 | namespace Utils |
27 | { |
28 | namespace Base64 |
29 | { |
30 | |
31 | Base64::Base64(const char *encodingTable) |
32 | { |
33 | if(encodingTable == nullptr) |
34 | { |
35 | encodingTable = BASE64_ENCODING_TABLE_MIME; |
36 | } |
37 | |
38 | size_t encodingTableLength = strlen(encodingTable); |
39 | if(encodingTableLength != 64) |
40 | { |
41 | encodingTable = BASE64_ENCODING_TABLE_MIME; |
42 | encodingTableLength = 64; |
43 | } |
44 | |
45 | memcpy(m_mimeBase64EncodingTable, encodingTable, encodingTableLength); |
46 | |
47 | memset((void *)m_mimeBase64DecodingTable, 0, 256); |
48 | |
49 | for(uint32_t i = 0; i < encodingTableLength; ++i) |
50 | { |
51 | uint32_t index = static_cast<uint32_t>(m_mimeBase64EncodingTable[i]); |
52 | m_mimeBase64DecodingTable[index] = static_cast<uint8_t>(i); |
53 | } |
54 | |
55 | m_mimeBase64DecodingTable[(uint32_t)'='] = SENTINEL_VALUE; |
56 | } |
57 | |
58 | Aws::String Base64::Encode(const Aws::Utils::ByteBuffer& buffer) const |
59 | { |
60 | size_t bufferLength = buffer.GetLength(); |
61 | size_t blockCount = (bufferLength + 2) / 3; |
62 | size_t remainderCount = (bufferLength % 3); |
63 | |
64 | Aws::String outputString; |
65 | outputString.reserve(CalculateBase64EncodedLength(buffer)); |
66 | |
67 | for(size_t i = 0; i < bufferLength; i += 3 ) |
68 | { |
69 | uint32_t block = buffer[ i ]; |
70 | |
71 | block <<= 8; |
72 | if (i + 1 < bufferLength) |
73 | { |
74 | block = block | buffer[ i + 1 ]; |
75 | } |
76 | |
77 | block <<= 8; |
78 | if (i + 2 < bufferLength) |
79 | { |
80 | block = block | buffer[ i + 2 ]; |
81 | } |
82 | |
83 | outputString.push_back(m_mimeBase64EncodingTable[(block >> 18) & 0x3F]); |
84 | outputString.push_back(m_mimeBase64EncodingTable[(block >> 12) & 0x3F]); |
85 | outputString.push_back(m_mimeBase64EncodingTable[(block >> 6) & 0x3F]); |
86 | outputString.push_back(m_mimeBase64EncodingTable[block & 0x3F]); |
87 | } |
88 | |
89 | if(remainderCount > 0) |
90 | { |
91 | outputString[blockCount * 4 - 1] = '='; |
92 | if(remainderCount == 1) |
93 | { |
94 | outputString[blockCount * 4 - 2] = '='; |
95 | } |
96 | } |
97 | |
98 | return outputString; |
99 | } |
100 | |
101 | Aws::Utils::ByteBuffer Base64::Decode(const Aws::String& str) const |
102 | { |
103 | size_t decodedLength = CalculateBase64DecodedLength(str); |
104 | |
105 | Aws::Utils::ByteBuffer buffer(decodedLength); |
106 | |
107 | const char* rawString = str.c_str(); |
108 | size_t blockCount = str.length() / 4; |
109 | for(size_t i = 0; i < blockCount; ++i) |
110 | { |
111 | size_t stringIndex = i * 4; |
112 | |
113 | uint32_t value1 = m_mimeBase64DecodingTable[uint32_t(rawString[stringIndex])]; |
114 | uint32_t value2 = m_mimeBase64DecodingTable[uint32_t(rawString[++stringIndex])]; |
115 | uint32_t value3 = m_mimeBase64DecodingTable[uint32_t(rawString[++stringIndex])]; |
116 | uint32_t value4 = m_mimeBase64DecodingTable[uint32_t(rawString[++stringIndex])]; |
117 | |
118 | size_t bufferIndex = i * 3; |
119 | buffer[bufferIndex] = static_cast<uint8_t>((value1 << 2) | ((value2 >> 4) & 0x03)); |
120 | if(value3 != SENTINEL_VALUE) |
121 | { |
122 | buffer[++bufferIndex] = static_cast<uint8_t>(((value2 << 4) & 0xF0) | ((value3 >> 2) & 0x0F)); |
123 | if(value4 != SENTINEL_VALUE) |
124 | { |
125 | buffer[++bufferIndex] = static_cast<uint8_t>((value3 & 0x03) << 6 | value4); |
126 | } |
127 | } |
128 | } |
129 | |
130 | return buffer; |
131 | } |
132 | |
133 | size_t Base64::CalculateBase64DecodedLength(const Aws::String& b64input) |
134 | { |
135 | const size_t len = b64input.length(); |
136 | if(len < 2) |
137 | { |
138 | return 0; |
139 | } |
140 | |
141 | size_t padding = 0; |
142 | |
143 | if (b64input[len - 1] == '=' && b64input[len - 2] == '=') //last two chars are = |
144 | padding = 2; |
145 | else if (b64input[len - 1] == '=') //last char is = |
146 | padding = 1; |
147 | |
148 | return (len * 3 / 4 - padding); |
149 | } |
150 | |
151 | size_t Base64::CalculateBase64EncodedLength(const Aws::Utils::ByteBuffer& buffer) |
152 | { |
153 | return 4 * ((buffer.GetLength() + 2) / 3); |
154 | } |
155 | |
156 | } // namespace Base64 |
157 | } // namespace Utils |
158 | } // namespace Aws |