1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-12-06 00:51:00 +01:00

Encapsulate invalidBase32, avoid 0xFF magic number

This keeps things fast by making the function inline, but also prevents
people from having to know about the `0xFF` implementation detail
directly, instead making one go through a `std::optional` (which could be
fused away with a sufficiently smart compiler).

Additionally, the base "nix32" implementation is moved to its own header
file pair, as it is logically distinct and prior to the `Hash` data
type. It would probably be nice to do this with all the hash format
implementations.
This commit is contained in:
John Ericson 2025-08-04 14:31:14 -04:00
parent 6ab8cbe31a
commit 23c87d8a21
8 changed files with 101 additions and 38 deletions

View file

@ -11,6 +11,7 @@
#include "nix/util/archive.hh"
#include "nix/util/configuration.hh"
#include "nix/util/split.hh"
#include "nix/util/base-nix-32.hh"
#include <sys/types.h>
#include <sys/stat.h>
@ -71,39 +72,10 @@ static std::string printHash16(const Hash & hash)
return buf;
}
// omitted: E O U T
constexpr char nix32Chars[] = "0123456789abcdfghijklmnpqrsvwxyz";
constexpr const std::array<unsigned char, 256> reverseNix32Map = [] {
std::array<unsigned char, 256> map{};
for (size_t i = 0; i < map.size(); ++i)
map[i] = 0xFF; // invalid
for (unsigned char i = 0; i < 32; ++i)
map[static_cast<unsigned char>(nix32Chars[i])] = i;
return map;
}();
static std::string printHash32(const Hash & hash)
{
assert(hash.hashSize);
size_t len = hash.base32Len();
assert(len);
std::string s;
s.reserve(len);
for (int n = (int) len - 1; n >= 0; n--) {
unsigned int b = n * 5;
unsigned int i = b / 8;
unsigned int j = b % 8;
unsigned char c = (hash.hash[i] >> j) | (i >= hash.hashSize - 1 ? 0 : hash.hash[i + 1] << (8 - j));
s.push_back(nix32Chars[c & 0x1f]);
}
return s;
return BaseNix32::encode({&hash.hash[0], hash.hashSize});
}
std::string printHash16or32(const Hash & hash)
@ -229,11 +201,13 @@ Hash::Hash(std::string_view rest, HashAlgorithm algo, bool isSRI)
for (unsigned int n = 0; n < rest.size(); ++n) {
char c = rest[rest.size() - n - 1];
unsigned char digit = reverseNix32Map[static_cast<unsigned char>(c)];
auto digit_opt = BaseNix32::lookupReverse(c);
if (digit == 0xFF)
if (!digit_opt)
throw BadHash("invalid base-32 hash: '%s'", rest);
uint8_t digit = std::move(*digit_opt);
unsigned int b = n * 5;
unsigned int i = b / 8;
unsigned int j = b % 8;