Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/libcmd/misc-store-flags.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ static void hashFormatCompleter(AddCompletions & completions, size_t index, std:

Args::Flag hashFormatWithDefault(std::string && longName, HashFormat * hf)
{
assert(*hf == nix::HashFormat::SRI);
assert(std::holds_alternative<HashFormatSRI>(hf->raw));
return Args::Flag{
.longName = std::move(longName),
.description = "Hash format (`base16`, `nix32`, `base64`, `sri`). Default: `sri`.",
Expand Down
2 changes: 1 addition & 1 deletion src/libexpr/primops.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4596,7 +4596,7 @@ static void prim_convertHash(EvalState & state, const PosIdx pos, Value ** args,
HashFormat hf = parseHashFormat(
state.forceStringNoCtx(*iteratorToHashFormat->value, pos, "while evaluating the attribute 'toHashFormat'"));

v.mkString(Hash::parseAny(hash, ha).to_string(hf, hf == HashFormat::SRI), state.mem);
v.mkString(Hash::parseAny(hash, ha).to_string(hf, std::holds_alternative<HashFormatSRI>(hf.raw)), state.mem);
}

static RegisterPrimOp primop_convertHash({
Expand Down
22 changes: 22 additions & 0 deletions src/libutil-tests/base-n.cc
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,26 @@ INSTANTIATE_TEST_SUITE_P(
Base64TrailingParseCase{
"7g91TBvYoYQorRTqo+rYD/i5YnWvUBLnqDhPHxBJDaBW7smuPMeRp6E6JOFuVN9bzN0QnH1ToUU0u9c2CjALEQ== cheesecake"}));

/* ----------------------------------------------------------------------------
* parseBase, parseBaseOpt, printBase
* --------------------------------------------------------------------------*/

TEST(base, testRoundTripPrintParse)
{
for (const Base base : {Base::Base64, Base::Nix32, Base::Base16}) {
ASSERT_EQ(parseBase(printBase(base)), base);
ASSERT_EQ(*parseBaseOpt(printBase(base)), base);
}
}

TEST(base, testParseBaseOptReturnsNullopt)
{
ASSERT_EQ(parseBaseOpt("sha0042"), std::nullopt);
}

TEST(base, testParseBaseThrowsOnInvalid)
{
ASSERT_THROW(parseBase("invalid"), UsageError);
}

} // namespace nix
2 changes: 1 addition & 1 deletion src/libutil-tests/hash.cc
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ TEST(hashParseExplicitFormatUnprefixed, testKnownSHA256Hashes1_wrongBase)

TEST(hashFormat, testRoundTripPrintParse)
{
for (const HashFormat hashFormat : {HashFormat::Base64, HashFormat::Nix32, HashFormat::Base16, HashFormat::SRI}) {
for (const HashFormat hashFormat : {HashFormat{Base::Base64}, {Base::Nix32}, {Base::Base16}, {HashFormat::SRI}}) {
ASSERT_EQ(parseHashFormat(printHashFormat(hashFormat)), hashFormat);
ASSERT_EQ(*parseHashFormatOpt(printHashFormat(hashFormat)), hashFormat);
}
Expand Down
126 changes: 126 additions & 0 deletions src/libutil/base-n.cc
Original file line number Diff line number Diff line change
@@ -1,13 +1,79 @@
#include <string_view>

#include "nix/util/array-from-string-literal.hh"
#include "nix/util/error.hh"
#include "nix/util/logging.hh"
#include "nix/util/util.hh"
#include "nix/util/base-n.hh"
#include "nix/util/base-nix-32.hh"

using namespace std::literals;

namespace nix {

std::optional<Base> parseBaseOpt(std::string_view s)
{
if (s == "base16")
return Base::Base16;
if (s == "nix32")
return Base::Nix32;
if (s == "base32") {
warn(R"("base32" is a deprecated alias for base encoding "nix32".)");
return Base::Nix32;
}
if (s == "base64")
return Base::Base64;
return std::nullopt;
}

Base parseBase(std::string_view s)
{
auto base = parseBaseOpt(s);
if (base)
return *base;
throw UsageError("unknown base encoding '%1%', expected 'base16', 'nix32', or 'base64'", s);
}

std::string_view printBase(Base base)
{
switch (base) {
case Base::Base16:
return "base16";
case Base::Nix32:
return "nix32";
case Base::Base64:
return "base64";
}
unreachable();
}

std::string_view printBaseDisplay(Base base)
{
switch (base) {
case Base::Base16:
return "base-16";
case Base::Nix32:
return "Nix base-32";
case Base::Base64:
return "base-64";
}
unreachable();
}

std::optional<Base> baseFromEncodedSize(size_t encodedSize, size_t decodedSize)
{
if (encodedSize == base16::encodedLength(decodedSize))
return Base::Base16;

if (encodedSize == BaseNix32::encodedLength(decodedSize))
return Base::Nix32;

if (encodedSize == base64::encodedLength(decodedSize))
return Base::Base64;

return std::nullopt;
}

constexpr static const std::array<char, 16> base16Chars = "0123456789abcdef"_arrayNoNull;

std::string base16::encode(std::span<const std::byte> b)
Expand Down Expand Up @@ -111,4 +177,64 @@ std::string base64::decode(std::string_view s)
return res;
}

namespace {

struct Base16Encoding final : BaseEncoding
{
std::string encode(std::span<const std::byte> data) const override
{
return base16::encode(data);
}

std::string decode(std::string_view s) const override
{
return base16::decode(s);
}
};

struct Nix32Encoding final : BaseEncoding
{
std::string encode(std::span<const std::byte> data) const override
{
return BaseNix32::encode(data);
}

std::string decode(std::string_view s) const override
{
return BaseNix32::decode(s);
}
};

struct Base64Encoding final : BaseEncoding
{
std::string encode(std::span<const std::byte> data) const override
{
return base64::encode(data);
}

std::string decode(std::string_view s) const override
{
return base64::decode(s);
}
};

const Base16Encoding base16Encoding;
const Nix32Encoding nix32Encoding;
const Base64Encoding base64Encoding;

} // anonymous namespace

const BaseEncoding & getBaseEncoding(Base base)
{
switch (base) {
case Base::Base16:
return base16Encoding;
case Base::Nix32:
return nix32Encoding;
case Base::Base64:
return base64Encoding;
}
unreachable();
}

} // namespace nix
Loading
Loading