| /* |
| * |
| * Copyright (c) 2021 Project CHIP Authors |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /** |
| * @file |
| * This file implements converting a Base38 String into an array of bytes. |
| * |
| */ |
| |
| #include "Base38Decode.h" |
| |
| namespace { |
| |
| static inline CHIP_ERROR decodeChar(char c, uint8_t & value) |
| { |
| static const int kBogus = 255; |
| // map of base38 charater to numeric value |
| // subtract 45 from the charater, then index into this array, if possible |
| const uint8_t decodes[] = { |
| 36, // '-', =45 |
| 37, // '.', =46 |
| kBogus, // '/', =47 |
| 0, // '0', =48 |
| 1, // '1', =49 |
| 2, // '2', =50 |
| 3, // '3', =51 |
| 4, // '4', =52 |
| 5, // '5', =53 |
| 6, // '6', =54 |
| 7, // '7', =55 |
| 8, // '8', =56 |
| 9, // '9', =57 |
| kBogus, // ':', =58 |
| kBogus, // ';', =59 |
| kBogus, // '<', =50 |
| kBogus, // '=', =61 |
| kBogus, // '>', =62 |
| kBogus, // '?', =63 |
| kBogus, // '@', =64 |
| 10, // 'A', =65 |
| 11, // 'B', =66 |
| 12, // 'C', =67 |
| 13, // 'D', =68 |
| 14, // 'E', =69 |
| 15, // 'F', =70 |
| 16, // 'G', =71 |
| 17, // 'H', =72 |
| 18, // 'I', =73 |
| 19, // 'J', =74 |
| 20, // 'K', =75 |
| 21, // 'L', =76 |
| 22, // 'M', =77 |
| 23, // 'N', =78 |
| 24, // 'O', =79 |
| 25, // 'P', =80 |
| 26, // 'Q', =81 |
| 27, // 'R', =82 |
| 28, // 'S', =83 |
| 29, // 'T', =84 |
| 30, // 'U', =85 |
| 31, // 'V', =86 |
| 32, // 'W', =87 |
| 33, // 'X', =88 |
| 34, // 'Y', =89 |
| 35, // 'Z', =90 |
| }; |
| if (c < '-' || c > 'Z') |
| { |
| return CHIP_ERROR_INVALID_INTEGER_VALUE; |
| } |
| uint8_t v = decodes[c - '-']; |
| if (v == kBogus) |
| { |
| return CHIP_ERROR_INVALID_INTEGER_VALUE; |
| } |
| value = v; |
| return CHIP_NO_ERROR; |
| } |
| |
| } // unnamed namespace |
| |
| namespace chip { |
| |
| CHIP_ERROR base38Decode(std::string base38, std::vector<uint8_t> & result) |
| { |
| result.clear(); |
| |
| size_t base38CharactersNumber = base38.length(); |
| size_t decodedBase38Characters = 0; |
| while (base38CharactersNumber > 0) |
| { |
| uint8_t base38CharactersInChunk; |
| uint8_t bytesInDecodedChunk; |
| |
| if (base38CharactersNumber >= kBase38CharactersNeededInNBytesChunk[2]) |
| { |
| base38CharactersInChunk = kBase38CharactersNeededInNBytesChunk[2]; |
| bytesInDecodedChunk = 3; |
| } |
| else if (base38CharactersNumber == kBase38CharactersNeededInNBytesChunk[1]) |
| { |
| base38CharactersInChunk = kBase38CharactersNeededInNBytesChunk[1]; |
| bytesInDecodedChunk = 2; |
| } |
| else if (base38CharactersNumber == kBase38CharactersNeededInNBytesChunk[0]) |
| { |
| base38CharactersInChunk = kBase38CharactersNeededInNBytesChunk[0]; |
| bytesInDecodedChunk = 1; |
| } |
| else |
| { |
| return CHIP_ERROR_INVALID_STRING_LENGTH; |
| } |
| |
| uint32_t value = 0; |
| |
| for (size_t i = base38CharactersInChunk; i > 0; i--) |
| { |
| uint8_t v = 0; |
| CHIP_ERROR err = decodeChar(base38[decodedBase38Characters + i - 1], v); |
| |
| if (err != CHIP_NO_ERROR) |
| { |
| return err; |
| } |
| |
| value = value * kRadix + v; |
| } |
| decodedBase38Characters += base38CharactersInChunk; |
| base38CharactersNumber -= base38CharactersInChunk; |
| |
| for (size_t i = 0; i < bytesInDecodedChunk; i++) |
| { |
| result.push_back(static_cast<uint8_t>(value)); |
| value >>= 8; |
| } |
| |
| if (value > 0) |
| { |
| // encoded value is too big to represent a correct chunk of size 1, 2 or 3 bytes |
| return CHIP_ERROR_INVALID_ARGUMENT; |
| } |
| } |
| return CHIP_NO_ERROR; |
| } |
| |
| } // namespace chip |