| 137 | } |
| 138 | |
| 139 | static dmtcp::string |
| 140 | decode(dmtcp::string const& encoded_string) |
| 141 | { |
| 142 | if (encoded_string.empty()) |
| 143 | return dmtcp::string(); |
| 144 | |
| 145 | size_t length_of_string = encoded_string.length(); |
| 146 | size_t pos = 0; |
| 147 | |
| 148 | // |
| 149 | // The approximate length (bytes) of the decoded string might be one or |
| 150 | // two bytes smaller, depending on the amount of trailing equal signs |
| 151 | // in the encoded string. This approximation is needed to reserve |
| 152 | // enough space in the string to be returned. |
| 153 | // |
| 154 | size_t approx_length_of_decoded_string = length_of_string / 4 * 3; |
| 155 | dmtcp::string ret; |
| 156 | ret.reserve(approx_length_of_decoded_string); |
| 157 | |
| 158 | while (pos < length_of_string) { |
| 159 | // |
| 160 | // Iterate over encoded input string in chunks. The size of all |
| 161 | // chunks except the last one is 4 bytes. |
| 162 | // |
| 163 | // The last chunk might be padded with equal signs or dots |
| 164 | // in order to make it 4 bytes in size as well, but this |
| 165 | // is not required as per RFC 2045. |
| 166 | // |
| 167 | // All chunks except the last one produce three output bytes. |
| 168 | // |
| 169 | // The last chunk produces at least one and up to three bytes. |
| 170 | // |
| 171 | |
| 172 | size_t pos_of_char_1 = pos_of_char(encoded_string[pos + 1]); |
| 173 | |
| 174 | // |
| 175 | // Emit the first output byte that is produced in each chunk: |
| 176 | // |
| 177 | ret.push_back(static_cast<dmtcp::string::value_type>( |
| 178 | ((pos_of_char(encoded_string[pos + 0])) << 2) + |
| 179 | ((pos_of_char_1 & 0x30) >> 4))); |
| 180 | |
| 181 | if ((pos + 2 < |
| 182 | length_of_string) && // Check for data that is not padded with equal |
| 183 | // signs (which is allowed by RFC 2045) |
| 184 | encoded_string[pos + 2] != '=' && |
| 185 | encoded_string[pos + 2] != |
| 186 | '.' // accept URL-safe base 64 strings, too, so check for '.' also. |
| 187 | ) { |
| 188 | // |
| 189 | // Emit a chunk's second byte (which might not be produced in the last |
| 190 | // chunk). |
| 191 | // |
| 192 | unsigned int pos_of_char_2 = pos_of_char(encoded_string[pos + 2]); |
| 193 | ret.push_back(static_cast<dmtcp::string::value_type>( |
| 194 | ((pos_of_char_1 & 0x0f) << 4) + ((pos_of_char_2 & 0x3c) >> 2))); |
| 195 | |
| 196 | if ((pos + 3 < length_of_string) && encoded_string[pos + 3] != '=' && |
no test coverage detected