flatten 20260225

This commit is contained in:
Timothy Prepscius
2026-02-25 12:39:24 -05:00
commit fa54be052a
315 changed files with 49791 additions and 0 deletions

96
tjp/core/bases/Base16.cpp Executable file
View File

@@ -0,0 +1,96 @@
// TJP COPYRIGHT HEADER
#ifdef TJP_CORE_HEADER_ONLY
#pragma once
#endif
#include <tjp/core/header_only/compile.h>
#include "Base16.h"
#include <resolv.h>
#include <memory.h>
#include <assert.h>
#include <tjp/core/assert/debug_assert.h>
#include <tjp/core/assert/handle_assert.hpp>
namespace tjp::core {
using b16d = b16_bin;
TJP_CORE_HEADER_ONLY_INLINE
size_t toBase16 (const b16d *in, size_t inSize, b16_char *out, size_t outSize)
{
const char *base16_charset = "0123456789abcdef";
handle_assert(outSize == 2 * inSize) {
return 0;
}
auto begin = in;
auto end = in + inSize;
for (auto *i = begin; i!=end; ++i)
{
int n1 = (int)*i & 0x0F;
int n2 = (int)*i >> 4 & 0x0F;
*out++ = base16_charset[n2];
*out++ = base16_charset[n1];
}
return 2*inSize;
}
TJP_CORE_HEADER_ONLY_INLINE
std::string toBase16 (const b16d *dataToEncode, size_t dataToEncodeLength)
{
std::string encodedData;
encodedData.resize(dataToEncodeLength*2);
toBase16(dataToEncode, dataToEncodeLength, encodedData.data(), encodedData.size());
return encodedData;
}
inline int getNibble (char c)
{
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
handle_assert(false)
;
return 0;
}
TJP_CORE_HEADER_ONLY_INLINE
size_t fromBase16 (const char *in, size_t inSize, b16d *out, size_t outSize)
{
handle_assert((inSize % 2 == 0) && (inSize == 2 * outSize)) {
return 0;
}
auto begin = in;
auto end = in + inSize;
for (auto *i = begin; i!=end; )
{
int n2 = getNibble(*i++);
int n1 = getNibble(*i++);
unsigned char c = n2 << 4 | n1;
*out++ = c;
}
return outSize;
}
} // namespace

104
tjp/core/bases/Base16.h Executable file
View File

@@ -0,0 +1,104 @@
// TJP COPYRIGHT HEADER
#pragma once
#include <string>
#include <vector>
#include <tjp/core/types/Types.h>
namespace tjp::core {
using b16_bin = u8;
using b16_char = char;
size_t fromBase16 (const b16_char *in, size_t inSize, b16_bin *out, size_t outSize);
inline
size_t base16EncodeSize(size_t size)
{
return size * 2;
}
inline
size_t base16DecodeSize(const b16_char *b, size_t size)
{
return size / 2;
}
template<typename T=b16_char>
std::vector<T> fromBase16 (const b16_char *b, size_t size)
{
auto decodeSize = base16DecodeSize(b, size);
std::vector<T> r(decodeSize / sizeof(T));
fromBase16((const b16_char *)b, size, (b16_bin *)r.data(), decodeSize);
return r;
}
template<typename U>
U fromBase16v (const b16_char *b, size_t size)
{
auto decodeSize = base16DecodeSize(b, size);
U r(decodeSize / sizeof(typename U::value_type));
fromBase16((const b16_char *)b, size, (b16_bin *)r.data(), decodeSize);
return r;
}
template<typename T=b16_char>
std::vector<T> fromBase16 (const std::string_view &block)
{
return fromBase16<T>(block.data(), block.size());
}
template<typename T>
bool fromBase16(T &t, const b16_char *b, size_t size)
{
return fromBase16(b, size, (b16_bin *)&t, sizeof(t)) == sizeof(t);
}
template<typename T>
bool fromBase16(T &t, const std::string_view &block)
{
return fromBase16(t, block.data(), block.size());
}
std::string toBase16 (const b16_bin *b, size_t size);
size_t toBase16 (const b16_bin *in, size_t inSize, b16_char *out, size_t outSize);
template<typename T>
std::string toBase16 (const T *b, size_t size)
{
return toBase16((const b16_bin *)b, sizeof(*b) * size);
}
//template<typename T>
//std::string toBase16 (const std::vector<T> &block)
//{
// return toBase16((b16_bin *)block.data(), sizeof(block[0]) * block.size());
//}
template<typename T>
std::string toBase16 (const T &block)
{
return toBase16((b16_bin *)block.data(), sizeof(typename T::value_type) * block.size());
}
template<typename T>
bool toBase16(const T &t, b16_char *out, size_t outSize)
{
return toBase16((b16_bin *)&t, sizeof(t), out, outSize) == outSize;
}
template<typename T>
bool toBase16(const T &t, const std::string_view &block)
{
return toBase16(t, (b16_char *)block.data(), block.size());
}
} // namespace
#ifdef TJP_CORE_HEADER_ONLY
#include "Base16.cpp"
#endif

88
tjp/core/bases/Base32.cpp Executable file
View File

@@ -0,0 +1,88 @@
// TJP COPYRIGHT HEADER
#include "Base32.h"
#include <base32/base32_crockford.hpp>
#include <base32/base32_rfc4648.hpp>
#include <resolv.h>
#include <memory.h>
#include <assert.h>
#include <tjp/core/assert/debug_assert.h>
#include <tjp/core/assert/handle_assert.hpp>
namespace tjp::core {
//using base32 = cppcodec::base32_rfc4648;
//using base32base = cppcodec::detail::base32_rfc4648;
using base32 = cppcodec::base32_crockford;
using base32base = cppcodec::detail::base32_crockford;
size_t base32EncodeSize(size_t size)
{
return base32::encoded_size(size);
}
size_t base32DecodeSize(const b32_char *b, size_t size)
{
auto maxSize = base32::decoded_max_size(size);
auto actualSize = maxSize;
if constexpr (base32base::generates_padding())
{
auto end = size;
auto i = end;
for (; i>0; --i)
{
if (!base32base::is_padding_symbol(b[i-1]))
break;
}
auto numPadding = end - i;
int paddingRemove = 0;
switch (numPadding) {
case 1:
case 2: paddingRemove = 1; break;
case 3: paddingRemove = 2; break;
case 4: paddingRemove = 3; break;
case 5:
case 6: paddingRemove = 4; break;
case 7:
case 8: paddingRemove = 5; break;
}
actualSize = maxSize - paddingRemove;
}
return actualSize;
}
using b32d = b32_bin;
size_t toBase32 (const b32d *in, size_t inSize, b32_char *out, size_t outSize)
{
auto size = base32::encode(out, outSize, in, inSize);
return size;
}
std::string toBase32 (const b32d *dataToEncode, size_t dataToEncodeLength)
{
std::string encodedData;
encodedData.resize(dataToEncodeLength*2);
return base32::encode(dataToEncode, dataToEncodeLength);
}
size_t fromBase32 (const char *in, size_t inSize, b32d *out, size_t outSize)
{
debug_assert(outSize == base32DecodeSize(in, inSize));
auto size = base32::decode(out, base32::decoded_max_size(inSize), in, inSize);
return size;
}
} // namespace

91
tjp/core/bases/Base32.h Executable file
View File

@@ -0,0 +1,91 @@
// TJP COPYRIGHT HEADER
#pragma once
#include <string>
#include <vector>
#include <tjp/core/types/Types.h>
namespace tjp::core {
using b32_bin = u8;
using b32_char = char;
size_t fromBase32 (const b32_char *in, size_t inSize, b32_bin *out, size_t outSize);
size_t base32EncodeSize(size_t size);
size_t base32DecodeSize(const b32_char *b, size_t size);
template<typename T=b32_char>
std::vector<T> fromBase32 (const b32_char *b, size_t size)
{
auto decodeSize = base32DecodeSize(b, size);
std::vector<T> r(decodeSize / sizeof(T));
fromBase32((const b32_char *)b, size, (b32_bin *)r.data(), decodeSize);
return r;
}
template<typename U>
U fromBase32v (const b32_char *b, size_t size)
{
auto decodeSize = base32DecodeSize(b, size);
U r(decodeSize / sizeof(typename U::value_type));
fromBase32((const b32_char *)b, size, (b32_bin *)r.data(), decodeSize);
return r;
}
template<typename T=b32_char>
std::vector<T> fromBase32 (const std::string_view &block)
{
return fromBase32<T>(block.data(), block.size());
}
template<typename T>
bool fromBase32(T &t, const b32_char *b, size_t size)
{
return fromBase32(b, size, (b32_bin *)&t, sizeof(t)) == sizeof(t);
}
template<typename T>
bool fromBase32(T &t, const std::string_view &block)
{
return fromBase32(t, block.data(), block.size());
}
std::string toBase32 (const b32_bin *b, size_t size);
size_t toBase32 (const b32_bin *in, size_t inSize, b32_char *out, size_t outSize);
template<typename T>
std::string toBase32 (const T *b, size_t size)
{
return toBase32((const b32_bin *)b, sizeof(*b) * size);
}
//template<typename T>
//std::string toBase32 (const std::vector<T> &block)
//{
// return toBase32((b32_bin *)block.data(), sizeof(block[0]) * block.size());
//}
template<typename T>
std::string toBase32 (const T &block)
{
return toBase32((b32_bin *)block.data(), sizeof(typename T::value_type) * block.size());
}
template<typename T>
bool toBase32(const T &t, b32_char *out, size_t outSize)
{
return toBase32((b32_bin *)&t, sizeof(t), out, outSize) == outSize;
}
template<typename T>
bool toBase32(const T &t, const std::string_view &block)
{
return toBase32(t, (b32_char *)block.data(), block.size());
}
} // namespace

362
tjp/core/bases/Base64.cpp Executable file
View File

@@ -0,0 +1,362 @@
// TJP COPYRIGHT HEADER
#ifdef TJP_CORE_HEADER_ONLY
#pragma once
#endif
#include <tjp/core/header_only/compile.h>
#include "Base64.h"
//#include <zlib/zlib.h>
//#include <resolv.h>
//#include <memory.h>
#include <string.h>
#include <tjp/core/assert/debug_assert.h>
#include <tjp/core/iterators/range.hpp>
namespace tjp {
namespace core {
namespace detail {
static const char Base64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const char Pad64 = '=';
#define Assert debug_assert
using u_char = unsigned char;
using u_int = unsigned int;
TJP_CORE_HEADER_ONLY_INLINE
int b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize) {
size_t datalength = 0;
u_char input[3];
u_char output[4];
size_t i;
while (2 < srclength) {
input[0] = *src++;
input[1] = *src++;
input[2] = *src++;
srclength -= 3;
output[0] = input[0] >> 2;
output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
output[3] = input[2] & 0x3f;
Assert(output[0] < 64);
Assert(output[1] < 64);
Assert(output[2] < 64);
Assert(output[3] < 64);
if (datalength + 4 > targsize)
return (-1);
target[datalength++] = Base64[output[0]];
target[datalength++] = Base64[output[1]];
target[datalength++] = Base64[output[2]];
target[datalength++] = Base64[output[3]];
}
/* Now we worry about padding. */
if (0 != srclength) {
/* Get what's left. */
input[0] = input[1] = input[2] = '\0';
for (i = 0; i < srclength; i++)
input[i] = *src++;
output[0] = input[0] >> 2;
output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
Assert(output[0] < 64);
Assert(output[1] < 64);
Assert(output[2] < 64);
if (datalength >= targsize)
return -1;
target[datalength++] = Base64[output[0]];
if (datalength >= targsize)
return -1;
target[datalength++] = Base64[output[1]];
if (srclength != 1)
{
if (datalength >= targsize)
return -1;
target[datalength++] = Base64[output[2]];
}
}
if (datalength > targsize)
return (-1);
if (targsize > datalength)
target[datalength] = '\0'; /* Returned value doesn't count \0. */
return (int)datalength;
}
/*
TJP, man I can't believe I had to do this.
So I made the b64_pton_l work with sizes for input, and outputs which don't have \0
*/
TJP_CORE_HEADER_ONLY_INLINE
int b64_pton_l(char const *src, size_t srcLength, u_char *target, size_t targsize)
{
const char *end = src + srcLength;
u_int tarindex, state;
int ch;
const char *pos;
state = 0;
tarindex = 0;
while (src != end && (ch = *src++) != '\0') {
if (isspace(ch)) /* Skip whitespace anywhere. */
continue;
if (ch == Pad64)
break;
pos = strchr(Base64, ch);
if (pos == 0) /* A non-base64 character. */
return (-1);
switch (state) {
case 0:
if (target) {
if (tarindex >= targsize)
return (-1);
target[tarindex] = (pos - Base64) << 2;
}
state = 1;
break;
case 1:
if (target) {
target[tarindex] |= (pos - Base64) >> 4;
if (tarindex + 1 >= targsize)
return (-1);
target[tarindex+1] = ((pos - Base64) & 0x0f)
<< 4 ;
}
tarindex++;
state = 2;
break;
case 2:
if (target) {
target[tarindex] |= (pos - Base64) >> 2;
if (tarindex + 1 >= targsize)
return (-1);
target[tarindex+1] = ((pos - Base64) & 0x03)
<< 6;
}
tarindex++;
state = 3;
break;
case 3:
if (target) {
if (tarindex >= targsize)
return (-1);
target[tarindex] |= (pos - Base64);
}
tarindex++;
state = 0;
break;
}
}
/*
* We are done decoding Base-64 chars. Let's see if we ended
* on a byte boundary, and/or with erroneous trailing characters.
*/
// if (ch == Pad64) { /* We got a pad char. */
// ch = *src++; /* Skip it, get next. */
// switch (state) {
// case 0: /* Invalid = in first position */
// case 1: /* Invalid = in second position */
// return (-1);
//
// case 2: /* Valid, means one byte of info */
// /* Skip any number of spaces. */
// for (; ch != '\0'; ch = *src++)
// if (!isspace(ch))
// break;
// /* Make sure there is another trailing = sign. */
// if (ch != Pad64)
// return (-1);
// ch = *src++; /* Skip the = */
// /* Fall through to "single trailing =" case. */
// /* FALLTHROUGH */
//
// case 3: /* Valid, means two bytes of info */
// /*
// * We know this char is an =. Is there anything but
// * whitespace after it?
// */
// for (; ch != '\0'; ch = *src++)
// if (!isspace(ch))
// return (-1);
//
// /*
// * Now make sure for cases 2 and 3 that the "extra"
// * bits that slopped past the last full byte were
// * zeros. If we don't check them, they become a
// * subliminal channel.
// */
// if (target && target[tarindex] != 0)
// return (-1);
// }
// } else {
// /*
// * We ended by seeing the end of the string. Make sure we
// * have no partial bytes lying around.
// */
// if (state != 0)
// return (-1);
// }
return (tarindex);
}
} // namespace
TJP_CORE_HEADER_ONLY_INLINE
size_t base64EncodeSize(size_t v)
{
if (v == 0)
return 0;
auto vm1 = v-1;
// 1 = 2 = 0 * 4 + 2
// 2 = 3 = 0 * 4 + 2 + 1
// 3 = 4 = 0 * 4 + 2 + 2
// 4 = 6 = 1 * 4 + 2 + 0
// 5 = 7 = 1 * 4 + 2 + 1
// 6 = 8
// 7 = 10 = 6+4
return (vm1 / 3 * 4 + 2) + (vm1 % 3);
}
TJP_CORE_HEADER_ONLY_INLINE
size_t base64DecodeSize(size_t v)
{
return v * 3 / 4;
}
TJP_CORE_HEADER_ONLY_INLINE
std::string toBase64 (const std::vector<char> &dataToEncode)
{
return toBase64(dataToEncode.data(), (int)dataToEncode.size());
}
TJP_CORE_HEADER_ONLY_INLINE
std::string toBase64 (const std::string_view &dataToEncode)
{
return toBase64(dataToEncode.data(), (int)dataToEncode.size());
}
TJP_CORE_HEADER_ONLY_INLINE
std::string toBase64 (const std::string &dataToEncode)
{
return toBase64(dataToEncode.data(), (int)dataToEncode.size());
}
TJP_CORE_HEADER_ONLY_INLINE
size_t toBase64 (const char *in, size_t inSize, char *out, size_t outSize)
{
return detail::b64_ntop(
(const unsigned char *)in, inSize,
out, outSize
);
}
TJP_CORE_HEADER_ONLY_INLINE
std::string toBase64 (const char *dataToEncode, size_t dataToEncodeLength)
{
std::string encodedData;
auto encodeSize = base64EncodeSize(dataToEncodeLength);
encodedData.resize(encodeSize);
auto encodedRealLength = toBase64(
dataToEncode, dataToEncodeLength,
encodedData.data(), encodeSize
);
debug_assert(encodedRealLength == encodeSize);
if (encodedRealLength == -1)
return {};
return encodedData;
}
TJP_CORE_HEADER_ONLY_INLINE
void padBase64(std::string &v)
{
auto paddingLength = (4 - (v.size() % 4)) % 4;
for (auto _ : range(paddingLength))
v.push_back('=');
}
TJP_CORE_HEADER_ONLY_INLINE
std::vector<char> fromBase64 (const std::string_view &dataToDecode)
{
return fromBase64(dataToDecode.data(), (int)dataToDecode.size());
}
TJP_CORE_HEADER_ONLY_INLINE
size_t fromBase64(const char *in, size_t inSize, char *out, size_t outSize)
{
return detail::b64_pton_l(
in, inSize,
(unsigned char *)out, outSize
);
}
TJP_CORE_HEADER_ONLY_INLINE
size_t fromBase64(const std::string_view &in, char *out, size_t outSize)
{
return detail::b64_pton_l(
in.data(), in.size(),
(unsigned char *)out, outSize
);
}
TJP_CORE_HEADER_ONLY_INLINE
std::vector<char> fromBase64 (const char *dataToDecode, size_t dataToDecodeLength)
{
std::vector<char> decodedData;
auto decodedBufferLength = dataToDecodeLength * 3 / 4 + 1 + 128;
decodedData.resize(decodedBufferLength);
auto decodedBufferRealLength = fromBase64(
dataToDecode, dataToDecodeLength,
decodedData.data(),
decodedBufferLength
);
debug_assert(decodedBufferRealLength <= base64DecodeSize(dataToDecodeLength));
decodedData.resize(decodedBufferRealLength);
return decodedData;
}
} // namespace
} // namespace

46
tjp/core/bases/Base64.h Executable file
View File

@@ -0,0 +1,46 @@
// TJP COPYRIGHT HEADER
#pragma once
#include <string>
#include <string_view>
#include <vector>
namespace tjp::core {
void padBase64 (std::string &);
size_t base64EncodeSize(size_t);
size_t base64DecodeSize(size_t);
std::string toBase64 (const std::vector<char> &block);
std::string toBase64 (const std::string_view &block);
std::string toBase64 (const std::string &block);
std::vector<char> fromBase64 (const std::string_view &b64);
std::string toBase64 (const char *b, size_t size);
std::vector<char> fromBase64 (const char *b, size_t size);
size_t toBase64 (const char *in, size_t inSize, char *out, size_t outSize);
size_t fromBase64(const char *in, size_t inSize, char *out, size_t outSize);
size_t fromBase64(const std::string_view &in, char *out, size_t outSize);
template<typename T>
T fromBase64(const std::string_view &in)
{
T t;
fromBase64((const char *)in.data(), in.size(), (char *)&t, sizeof(t));
return t;
}
template<typename T>
std::string toBase64(const T &t)
{
return toBase64((const char *)&t, sizeof(t));
}
} // namespace
#ifdef TJP_CORE_HEADER_ONLY
#include "Base64.cpp"
#endif

114
tjp/core/bases/Base64URL.cpp Executable file
View File

@@ -0,0 +1,114 @@
// TJP COPYRIGHT HEADER
#ifdef TJP_CORE_HEADER_ONLY
#pragma once
#endif
#include <tjp/core/header_only/compile.h>
#include "Base64URL.h"
namespace tjp::core {
/*
Base64 translates 24 bits into 4 ASCII characters at a time. First,
3 8-bit bytes are treated as 4 6-bit groups. Those 4 groups are
translated into ASCII characters. That is, each 6-bit number is treated
as an index into the ASCII character array.
If the final set of bits is less 8 or 16 instead of 24, traditional base64
would add a padding character. However, if the length of the data is
known, then padding can be eliminated.
One difference between the "standard" Base64 is two characters are different.
See RFC 4648 for details.
This is how we end up with the Base64 URL encoding.
*/
const char base64_url_alphabet[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
};
TJP_CORE_HEADER_ONLY_INLINE
std::string toBase64URL(const char *in, int len) {
std::string out;
int val =0, valb=-6;
unsigned int i = 0;
for (i = 0; i < len; i++) {
unsigned char c = in[i];
val = (val<<8) + c;
valb += 8;
while (valb >= 0) {
out.push_back(base64_url_alphabet[(val>>valb)&0x3F]);
valb -= 6;
}
}
if (valb > -6) {
out.push_back(base64_url_alphabet[((val<<8)>>(valb+8))&0x3F]);
}
return out;
}
TJP_CORE_HEADER_ONLY_INLINE
std::string toBase64URL(const char *in, size_t len) {
return toBase64URL(in, (int)len);
}
TJP_CORE_HEADER_ONLY_INLINE
std::vector<char> fromBase64URL(const char *in, int len) {
std::vector<char> out;
static std::vector<int> T;
if (T.empty())
{
T.resize(256, -1);
for (auto i =0; i < 64; i++) T[base64_url_alphabet[i]] = i;
}
unsigned int i;
int val = 0, valb = -8;
for (i = 0; i < len; i++) {
unsigned char c = in[i];
if (T[c] == -1) break;
val = (val<<6) + T[c];
valb += 6;
if (valb >= 0) {
out.push_back(char((val>>valb)&0xFF));
valb -= 8;
}
}
return out;
}
TJP_CORE_HEADER_ONLY_INLINE
std::vector<char> fromBase64URL(const char *in, size_t len) {
return fromBase64URL(in, (int)len);
}
TJP_CORE_HEADER_ONLY_INLINE
std::string toBase64URL (const std::vector<char> &block)
{
return toBase64URL(block.data(), block.size());
}
TJP_CORE_HEADER_ONLY_INLINE
std::string toBase64URL (const std::string_view &block)
{
return toBase64URL(block.data(), block.size());
}
TJP_CORE_HEADER_ONLY_INLINE
std::vector<char> fromBase64URL (const std::string_view &b64)
{
return fromBase64URL(b64.data(), b64.size());
}
} // namespace

22
tjp/core/bases/Base64URL.h Executable file
View File

@@ -0,0 +1,22 @@
// TJP COPYRIGHT HEADER
#pragma once
#include <string>
#include <string_view>
#include <vector>
namespace tjp::core {
std::string toBase64URL (const std::vector<char> &block);
std::string toBase64URL (const std::string_view &block);
std::vector<char> fromBase64URL (const std::string_view &b64);
std::string toBase64URL (const char *b, size_t size);
std::vector<char> fromBase64URL (const char *b, size_t size);
} // namespace
#ifdef TJP_CORE_HEADER_ONLY
#include "Base64URL.cpp"
#endif

310
tjp/core/bases/_remove/ntop.c Executable file
View File

@@ -0,0 +1,310 @@
/*
* Copyright (c) 1996-1999 by Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*/
/*
* Portions Copyright (c) 1995 by International Business Machines, Inc.
*
* International Business Machines, Inc. (hereinafter called IBM) grants
* permission under its copyrights to use, copy, modify, and distribute this
* Software with or without fee, provided that the above copyright notice and
* all paragraphs of this notice appear in all copies, and that the name of IBM
* not be used in connection with the marketing of any product incorporating
* the Software or modifications thereof, without specific, written prior
* permission.
*
* To the extent it has a right to do so, IBM grants an immunity from suit
* under its patents, if any, for the use, sale or manufacture of products to
* the extent that such products are used for performing Domain Name System
* dynamic updates in TCP/IP networks by means of the Software. No immunity is
* granted for any product per se or for any other function of any product.
*
* THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
* DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
* IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <ctype.h>
#include <resolv.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define Assert(Cond) if (!(Cond)) abort()
static const char Base64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const char Pad64 = '=';
/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
The following encoding technique is taken from RFC 1521 by Borenstein
and Freed. It is reproduced here in a slightly edited form for
convenience.
A 65-character subset of US-ASCII is used, enabling 6 bits to be
represented per printable character. (The extra 65th character, "=",
is used to signify a special processing function.)
The encoding process represents 24-bit groups of input bits as output
strings of 4 encoded characters. Proceeding from left to right, a
24-bit input group is formed by concatenating 3 8-bit input groups.
These 24 bits are then treated as 4 concatenated 6-bit groups, each
of which is translated into a single digit in the base64 alphabet.
Each 6-bit group is used as an index into an array of 64 printable
characters. The character referenced by the index is placed in the
output string.
Table 1: The Base64 Alphabet
Value Encoding Value Encoding Value Encoding Value Encoding
0 A 17 R 34 i 51 z
1 B 18 S 35 j 52 0
2 C 19 T 36 k 53 1
3 D 20 U 37 l 54 2
4 E 21 V 38 m 55 3
5 F 22 W 39 n 56 4
6 G 23 X 40 o 57 5
7 H 24 Y 41 p 58 6
8 I 25 Z 42 q 59 7
9 J 26 a 43 r 60 8
10 K 27 b 44 s 61 9
11 L 28 c 45 t 62 +
12 M 29 d 46 u 63 /
13 N 30 e 47 v
14 O 31 f 48 w (pad) =
15 P 32 g 49 x
16 Q 33 h 50 y
Special processing is performed if fewer than 24 bits are available
at the end of the data being encoded. A full encoding quantum is
always completed at the end of a quantity. When fewer than 24 input
bits are available in an input group, zero bits are added (on the
right) to form an integral number of 6-bit groups. Padding at the
end of the data is performed using the '=' character.
Since all base64 input is an integral number of octets, only the
-------------------------------------------------
following cases can arise:
(1) the final quantum of encoding input is an integral
multiple of 24 bits; here, the final unit of encoded
output will be an integral multiple of 4 characters
with no "=" padding,
(2) the final quantum of encoding input is exactly 8 bits;
here, the final unit of encoded output will be two
characters followed by two "=" padding characters, or
(3) the final quantum of encoding input is exactly 16 bits;
here, the final unit of encoded output will be three
characters followed by one "=" padding character.
*/
int
b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize) {
size_t datalength = 0;
u_char input[3];
u_char output[4];
size_t i;
while (2 < srclength) {
input[0] = *src++;
input[1] = *src++;
input[2] = *src++;
srclength -= 3;
output[0] = input[0] >> 2;
output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
output[3] = input[2] & 0x3f;
Assert(output[0] < 64);
Assert(output[1] < 64);
Assert(output[2] < 64);
Assert(output[3] < 64);
if (datalength + 4 > targsize)
return (-1);
target[datalength++] = Base64[output[0]];
target[datalength++] = Base64[output[1]];
target[datalength++] = Base64[output[2]];
target[datalength++] = Base64[output[3]];
}
/* Now we worry about padding. */
if (0 != srclength) {
/* Get what's left. */
input[0] = input[1] = input[2] = '\0';
for (i = 0; i < srclength; i++)
input[i] = *src++;
output[0] = input[0] >> 2;
output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
Assert(output[0] < 64);
Assert(output[1] < 64);
Assert(output[2] < 64);
if (datalength + 4 > targsize)
return (-1);
target[datalength++] = Base64[output[0]];
target[datalength++] = Base64[output[1]];
if (srclength == 1)
target[datalength++] = Pad64;
else
target[datalength++] = Base64[output[2]];
target[datalength++] = Pad64;
}
if (datalength >= targsize)
return (-1);
target[datalength] = '\0'; /* Returned value doesn't count \0. */
return (datalength);
}
libresolv_hidden_def (b64_ntop)
/* skips all whitespace anywhere.
converts characters, four at a time, starting at (or after)
src from base - 64 numbers into three 8 bit bytes in the target area.
it returns the number of data bytes stored at the target, or -1 on error.
*/
int
b64_pton (char const *src, u_char *target, size_t targsize)
{
int tarindex, state, ch;
char *pos;
state = 0;
tarindex = 0;
while ((ch = *src++) != '\0') {
if (isspace(ch)) /* Skip whitespace anywhere. */
continue;
if (ch == Pad64)
break;
pos = strchr(Base64, ch);
if (pos == 0) /* A non-base64 character. */
return (-1);
switch (state) {
case 0:
if (target) {
if ((size_t)tarindex >= targsize)
return (-1);
target[tarindex] = (pos - Base64) << 2;
}
state = 1;
break;
case 1:
if (target) {
if ((size_t)tarindex + 1 >= targsize)
return (-1);
target[tarindex] |= (pos - Base64) >> 4;
target[tarindex+1] = ((pos - Base64) & 0x0f)
<< 4 ;
}
tarindex++;
state = 2;
break;
case 2:
if (target) {
if ((size_t)tarindex + 1 >= targsize)
return (-1);
target[tarindex] |= (pos - Base64) >> 2;
target[tarindex+1] = ((pos - Base64) & 0x03)
<< 6;
}
tarindex++;
state = 3;
break;
case 3:
if (target) {
if ((size_t)tarindex >= targsize)
return (-1);
target[tarindex] |= (pos - Base64);
}
tarindex++;
state = 0;
break;
default:
abort();
}
}
/*
* We are done decoding Base-64 chars. Let's see if we ended
* on a byte boundary, and/or with erroneous trailing characters.
*/
if (ch == Pad64) { /* We got a pad char. */
ch = *src++; /* Skip it, get next. */
switch (state) {
case 0: /* Invalid = in first position */
case 1: /* Invalid = in second position */
return (-1);
case 2: /* Valid, means one byte of info */
/* Skip any number of spaces. */
for ((void)NULL; ch != '\0'; ch = *src++)
if (!isspace(ch))
break;
/* Make sure there is another trailing = sign. */
if (ch != Pad64)
return (-1);
ch = *src++; /* Skip the = */
/* Fall through to "single trailing =" case. */
/* FALLTHROUGH */
case 3: /* Valid, means two bytes of info */
/*
* We know this char is an =. Is there anything but
* whitespace after it?
*/
for ((void)NULL; ch != '\0'; ch = *src++)
if (!isspace(ch))
return (-1);
/*
* Now make sure for cases 2 and 3 that the "extra"
* bits that slopped past the last full byte were
* zeros. If we don't check them, they become a
* subliminal channel.
*/
if (target && target[tarindex] != 0)
return (-1);
}
} else {
/*
* We ended by seeing the end of the string. Make sure we
* have no partial bytes lying around.
*/
if (state != 0)
return (-1);
}
return (tarindex);
}

View File

@@ -0,0 +1,36 @@
// TJP COPYRIGHT HEADER
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/bases/Base64.h>
namespace tjp::core {
namespace {
SCENARIO("base16")
{
GIVEN("size calculations")
{
std::vector<char> x;
x.reserve(512);
for (auto i=0; i<512; i++)
{
x.resize(i);
for (auto j=0; j<i; ++j)
x[j] = j*3;
auto e = base64EncodeSize(i);
auto enc = toBase64(x);
REQUIRE(enc.size() == e);
auto d = base64DecodeSize(e);
auto dec = fromBase64(enc);
REQUIRE(d == i);
REQUIRE(dec == x);
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,58 @@
// TJP COPYRIGHT HEADER
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/bases/Base32.h>
namespace tjp::core {
namespace {
SCENARIO("base32")
{
GIVEN("size calculations")
{
std::vector<char> x;
x.reserve(512);
for (auto i=0; i<512; i++)
{
x.resize(i);
for (auto j=0; j<i; ++j)
x[j] = i+j*3;
auto e = base32EncodeSize(i);
auto enc = toBase32(x);
REQUIRE(enc.size() == e);
auto d = base32DecodeSize(enc.data(), e);
REQUIRE(d == i);
auto dec = fromBase32(enc);
REQUIRE(d == i);
auto equals = dec == x;
REQUIRE(equals);
}
}
GIVEN("size u32")
{
auto encodeSize1 = base32EncodeSize(1);
REQUIRE(encodeSize1 < 16);
auto encodeSize2 = base32EncodeSize(2);
REQUIRE(encodeSize2 < 16);
auto encodeSize4 = base32EncodeSize(4);
REQUIRE(encodeSize4 < 16);
auto encodeSize6 = base32EncodeSize(6);
REQUIRE(encodeSize6 < 16);
auto encodeSize8 = base32EncodeSize(8);
REQUIRE(encodeSize8 < 16);
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,36 @@
// TJP COPYRIGHT HEADER
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/bases/Base64.h>
namespace tjp::core {
namespace {
SCENARIO("base64")
{
GIVEN("size calculations")
{
std::vector<char> x;
x.reserve(512);
for (auto i=0; i<512; i++)
{
x.resize(i);
for (auto j=0; j<i; ++j)
x[j] = j*3;
auto e = base64EncodeSize(i);
auto enc = toBase64(x);
REQUIRE(enc.size() == e);
auto d = base64DecodeSize(e);
auto dec = fromBase64(enc);
REQUIRE(d == i);
REQUIRE(dec == x);
}
}
}
} // namespace
} // namespace