レポジトリ種類: Mercurial

#include <algorithm>
#include <cstddef>
#include <iterator>
#include <stdexcept>
#include <string>

#include "base32.hh"

int Base32::char_to_val(char c) {
  std::string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
  auto it = std::find(alphabet.begin(), alphabet.end(), c);
  return (it != alphabet.end()) ? std::distance(alphabet.begin(), it) : -1;
}

std::vector<unsigned char> Base32::decode(const std::string &encoded) {
  size_t encoded_len = encoded.length();
  size_t padding = 0;
  for (int i = encoded_len - 1; i >= 0 && encoded[i] == '='; --i) {
    ++padding;
  }

  size_t out_len = (encoded_len - padding) * 5 / 8;
  if (out_len == 0) return {};

  std::vector<unsigned char> decoded(out_len);

  int buffer = 0, bits_left = 0, count = 0;
  Base32 b32;
  for (size_t i = 0; i < encoded_len - padding; ++i) {
    int val = b32.char_to_val(encoded[i]);
    if (val < 0) {
      throw std::runtime_error("Base32エンコードした文字の中に不正な文字があります。");
    }

    buffer <<= 5;
    buffer |= val;
    bits_left += 5;

    if (bits_left >= 8) {
      decoded[count++] = static_cast<unsigned char>(buffer >> (bits_left - 8));
      bits_left -= 8;
    }
  }

  decoded.resize(count);
  return decoded;
}