[+] AuCrypto::BCrypt

> GetForcedMinRounds
> GenSalt
> HashPW
> HashPWEx
> CheckPassword
> CheckPasswordEx
[*] Refactor AuCompression APIs
[*] Clean up AuTryConstructs
[+] Internal compression API for compression based interceptors
[+] Root-level input stream arg check for all compression apis (harden)
[*] Clean up AuCompression code
[+] Solar Designer / OpenWall blowfish crypt
[*] BlowCrypt: accept length input parameter
[*] Split locale into 2 source files
[-] Ugly comment from Open.Win32.cpp. TODO: Readd later. Might warn on empty string bc it makes sense given, "." and "/" normalizes to nothing, and memory pre-idc-if-drops are dropped siliently.
This commit is contained in:
Reece Wilson 2022-09-15 20:48:50 +01:00
parent 9c25b112a3
commit 8844e8fe64
35 changed files with 2023 additions and 726 deletions

View File

@ -12,7 +12,7 @@ namespace Aurora::Compression
/**
Compresses an in memory blob with zstandard
*/
AUKN_SYM bool Compress(const Memory::MemoryViewRead &source, Memory::ByteBuffer &out, int compressionLevel = 3);
AUKN_SYM bool Compress(const Memory::MemoryViewRead &source, Memory::ByteBuffer &out, int uCompressionLevel = 3);
/**
Decompresses an in memory blob with zstandard

View File

@ -1,7 +1,7 @@
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: CompressionInfo.hpp
File: CompressInfo.hpp
Date: 2021-7-14
Author: Reece
***/
@ -9,9 +9,9 @@
namespace Aurora::Compression
{
struct CompressionInfo
struct CompressInfo
{
AU_COPY_MOVE_DEF(CompressionInfo);
AU_COPY_MOVE_DEF(CompressInfo);
ECompressionType type;
@ -31,12 +31,12 @@ namespace Aurora::Compression
* BZIP: 0 <= x >= 9
*
*/
AuInt8 compressionLevel {6};
AuInt8 uCompressionLevel {6};
/**
* @brief LZMA: 5 <= fb <= 273, default = 32
*/
AuUInt32 fbWordSize {32};
AuUInt32 uFbWordSize {32};
/**
* LZMA only
@ -44,14 +44,14 @@ namespace Aurora::Compression
* (1 << 12) <= dictSize <= (3 << 29) for 64-bit version
* default = (1 << 24)
*/
AuUInt32 dictSize{};
AuUInt32 uDictSize{};
/**
* @brief 64KiB is a recommended "small" block size
*/
AuUInt16 lz4BlockSize {};
AuUInt16 uLz4BlockSize {};
bool hasWindowbits {true};
bool bHasWindowbits {true};
/**
* @brief DEFLATE related variabl
@ -63,28 +63,28 @@ namespace Aurora::Compression
* GZip: 0 <= x >= 15,
* recommended: 15
*/
AuUInt8 windowBits {15};
AuUInt8 uWindowBits {15};
/**
* @brief Internal output buffer size.
* Internal swap page is undefined.
*/
AuUInt32 internalStreamSize { 10 * 4096 };
AuUInt32 uInternalStreamSize { 10 * 4096 };
AuUInt8 threads {1};
AuUInt8 uThreads {1};
bool bLZ4AutoFlush {false};
inline CompressionInfo(ECompressionType alg) : type(alg)
inline CompressInfo(ECompressionType alg) : type(alg)
{
}
inline CompressionInfo(ECompressionType alg, AuUInt32 bufferSize) : type(alg), internalStreamSize(bufferSize)
inline CompressInfo(ECompressionType alg, AuUInt32 bufferSize) : type(alg), uInternalStreamSize(bufferSize)
{
}
; };
};
struct DecompressInfo
{
@ -98,24 +98,24 @@ namespace Aurora::Compression
/**
* @brief Internal output buffer size. Internal swap page is undefined.
*/
AuUInt32 internalStreamSize { 10 * 4096 };
AuUInt32 uInternalStreamSize { 10 * 4096 };
/**
* @brief Flag for headerless decompression streams
*/
bool hasWindowbits {true};
bool bHasWindowbits {true};
/**
* @brief Flag for headerless decompression streams
*/
AuInt8 windowBits {15};
AuInt8 uWindowBits {15};
inline DecompressInfo(ECompressionType alg) : alg(alg)
{
}
inline DecompressInfo(ECompressionType alg, AuUInt32 bufferSize) : alg(alg), internalStreamSize(bufferSize)
inline DecompressInfo(ECompressionType alg, AuUInt32 bufferSize) : alg(alg), uInternalStreamSize(bufferSize)
{
}

View File

@ -54,5 +54,5 @@ namespace Aurora::Compression
* (and features of) the io subsystem.
*
*/
AUKN_SYM bool Compress(const CompressionPipe &stream, const CompressionInfo &parameters);
AUKN_SYM bool Compress(const CompressionPipe &stream, const CompressInfo &parameters);
}

View File

@ -14,10 +14,10 @@ namespace Aurora::Compression
/**
* @brief
*/
AUKN_SHARED_API(Decompressor, ICompressionStream, const AuSPtr<IO::IStreamReader> &reader, const DecompressInfo &info);
AUKN_SHARED_API(Decompressor, ICompressionStream, const AuSPtr<IO::IStreamReader> &pReader, const DecompressInfo &info);
/**
* @brief
*/
AUKN_SHARED_API(Compressor, ICompressionStream, const AuSPtr<IO::IStreamReader> &reader, const CompressionInfo &info);
AUKN_SHARED_API(Compressor, ICompressionStream, const AuSPtr<IO::IStreamReader> &pReader, const CompressInfo &info);
}

View File

@ -0,0 +1,24 @@
/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: BCrypt.hpp
Date: 2022-9-15
Author: Reece
Note: MD5 ($1$), the other numberic methods, and non-standard unix fuckery (ie: $sha1$) isn't implemented.
This API implements $2x$-class password hashing and verification
***/
#pragma once
namespace Aurora::Crypto::BCrypt
{
AUKN_SYM int GetForcedMinRounds();
AUKN_SYM AuString GenSalt(int rounds);
AUKN_SYM AuString HashPW(const AuString &password, const AuString &salt);
AUKN_SYM AuString HashPWEx(const Memory::MemoryViewRead &password, const AuString &salt);
AUKN_SYM bool CheckPassword(const AuString &password, const AuString &hashedPassword);
AUKN_SYM bool CheckPasswordEx(const Memory::MemoryViewRead &password, const AuString &hashedPassword);
}

View File

@ -20,18 +20,18 @@ namespace Aurora::Compression
if (!destination.length && !destination.ptr)
{
return {0, this->_outbuffer.RemainingBytes()};
return {0, this->pOutputBuffer_->RemainingBytes()};
}
if (ingestUntilEOS)
{
while (this->_outbuffer.RemainingBytes() < destination.length)
while (this->pOutputBuffer_->RemainingBytes() < destination.length)
{
auto toRead = destination.length ? AuUInt32(destination.length - this->_outbuffer.RemainingBytes()) : 10 * 1024;
auto toRead = destination.length ? AuUInt32(destination.length - this->pOutputBuffer_->RemainingBytes()) : 10 * 1024;
if (Ingest_s(toRead).second == 0)
{
if (!this->_outbuffer.RemainingBytes(true))
if (!this->pOutputBuffer_->RemainingBytes(true))
{
return {};
}
@ -43,14 +43,14 @@ namespace Aurora::Compression
}
}
len = this->_outbuffer.Read(destination.ptr, destination.length, destination.ptr == nullptr);
len = this->pOutputBuffer_->Read(destination.ptr, destination.length, destination.ptr == nullptr);
return {read, len};
}
AuUInt32 BaseStream::GetAvailableProcessedBytes()
{
AU_LOCK_GUARD(this->_spinlock);
return this->_outbuffer.RemainingBytes(true);
return this->pOutputBuffer_->RemainingBytes(true);
}
AuUInt32 BaseStream::Read(const Memory::MemoryViewWrite & /*opt*/ destination)
@ -58,15 +58,15 @@ namespace Aurora::Compression
AU_LOCK_GUARD(this->_spinlock);
if (!destination.length && !destination.ptr)
{
return this->_outbuffer.RemainingBytes();
return this->pOutputBuffer_->RemainingBytes();
}
return this->_outbuffer.Read(destination.ptr, destination.length, destination.ptr == nullptr);
return this->pOutputBuffer_->Read(destination.ptr, destination.length, destination.ptr == nullptr);
}
bool BaseStream::GoBackByProcessedN(AuUInt32 offset)
{
AU_LOCK_GUARD(this->_spinlock);
return this->_outbuffer.ReaderTryGoBack(offset);
return this->pOutputBuffer_->ReaderTryGoBack(offset);
}
bool BaseStream::GoForwardByProcessedN(AuUInt32 offset)
@ -76,7 +76,7 @@ namespace Aurora::Compression
{
return true;
}
return this->_outbuffer.ReaderTryGoForward(offset);
return this->pOutputBuffer_->ReaderTryGoForward(offset);
}
AuStreamReadWrittenPair_t BaseStream::Ingest(AuUInt32 bytesFromUnprocessedInputSource)
@ -91,15 +91,35 @@ namespace Aurora::Compression
return Ingest_s(bytesFromUnprocessedInputSource);
}
bool BaseStream::IsValid()
{
return this->uBufferSize_ ? (this->pOutputBuffer_ && this->pOutputBuffer_->IsValid()) : true;
}
AuSPtr<Memory::ByteBuffer> BaseStream::GetBuffer()
{
return this->pOutputBuffer_;
}
void BaseStream::SetBuffer(const AuSPtr<Memory::ByteBuffer> &pBuffer)
{
if (!pBuffer)
{
this->pOutputBuffer_ = AuUnsafeRaiiToShared(&this->_outbufferOwned);
}
else
{
this->pOutputBuffer_ = pBuffer;
}
}
bool BaseStream::Write(const void *a, AuUInt32 length)
{
auto written = this->_outbuffer.Write(reinterpret_cast<const AuUInt8 *>(a),
length);
return written == length;
return this->pOutputBuffer_->Write(reinterpret_cast<const AuUInt8 *>(a), length) == length;
}
AuUInt32 BaseStream::GetInternalBufferSize()
{
return this->_outbuffer.allocSize;
return this->pOutputBuffer_->allocSize;
}
}

View File

@ -11,12 +11,14 @@
namespace Aurora::Compression
{
struct BaseStream : public ICompressionStream, protected IngestableReadBase
struct BaseStream : ICompressionStream, protected IngestableReadBase
{
BaseStream(int bufferSize = 4096 * 4) : _outbuffer(bufferSize)
{}
inline BaseStream(AuUInt32 bufferSize = 4096 * 4) : _outbufferOwned(bufferSize), uBufferSize_(bufferSize)
{
SetBuffer({});
}
virtual ~BaseStream()
inline virtual ~BaseStream()
{}
virtual bool Init(const AuSPtr<IO::IStreamReader> &reader) = 0;
@ -34,20 +36,27 @@ namespace Aurora::Compression
virtual AuStreamReadWrittenPair_t Ingest(AuUInt32 bytesFromUnprocessedInputSource) override;
virtual bool Flush() override
inline virtual bool Flush() override
{
return false;
}
virtual bool Finish() override
inline virtual bool Finish() override
{
return false;
}
bool IsValid();
AuSPtr<Memory::ByteBuffer> GetBuffer();
void SetBuffer(const AuSPtr<Memory::ByteBuffer> &pBuffer);
protected:
virtual AuStreamReadWrittenPair_t Ingest_s(AuUInt32 bytesFromUnprocessedInputSource) = 0;
Memory::ByteBuffer _outbuffer;
AuSPtr<Memory::ByteBuffer> pOutputBuffer_;
Memory::ByteBuffer _outbufferOwned;
AuThreadPrimitives::SpinLock _spinlock;
AuUInt32 uBufferSize_;
};
}

View File

@ -28,27 +28,33 @@
namespace Aurora::Compression
{
AUKN_SYM ICompressionStream *CompressorNew(const AuSPtr<IO::IStreamReader> &reader, const CompressionInfo &ref)
AUKN_SYM ICompressionStream *CompressorNew(const AuSPtr<IO::IStreamReader> &pReader, const CompressInfo &ref)
{
CompressionInfo info = ref;
BaseStream *ret {};
AuInt8 bits;
CompressInfo info = ref;
BaseStream *pRet {};
AuInt8 bits {};
if (!pReader)
{
SysPushErrorArg("Missing deflated stream pReader");
return nullptr;
}
switch (info.type)
{
#if defined(_AUHAS_ZSTD)
case ECompressionType::eZSTD:
ret = _new ZSTDDeflate(info);
pRet = _new ZSTDDeflate(info);
break;
#endif
case ECompressionType::eBZIP2:
#if defined(_AUHAS_BZIP2)
ret = _new BZIPDeflate(info);
pRet = _new BZIPDeflate(info);
break;
#endif
#if defined(_AUHAS_LZ4)
case ECompressionType::eLZ4:
ret = new LZ4Deflate(info);
pRet = new LZ4Deflate(info);
break;
#endif
#if defined(_AUHAS_ZLIB)
@ -61,28 +67,28 @@ namespace Aurora::Compression
return {};
}
ret = _new ZIPDeflate(info, bits);
pRet = _new ZIPDeflate(info, bits);
break;
#endif
default:
ret = nullptr;
pRet = nullptr;
break;
}
if (ret)
if (pRet)
{
if (!ret->Init(reader))
if (!pRet->Init(pReader))
{
delete ret;
ret = nullptr;
delete pRet;
pRet = nullptr;
}
}
return ret;
return pRet;
}
AUKN_SYM void CompressorRelease(ICompressionStream *stream)
AUKN_SYM void CompressorRelease(ICompressionStream *pStream)
{
AuSafeDelete<BaseStream *>(stream);
AuSafeDelete<BaseStream *>(pStream);
}
}

View File

@ -28,28 +28,34 @@
namespace Aurora::Compression
{
AUKN_SYM ICompressionStream *DecompressorNew(const AuSPtr<IO::IStreamReader> &reader, const DecompressInfo &ref)
AUKN_SYM ICompressionStream *DecompressorNew(const AuSPtr<IO::IStreamReader> &pReader, const DecompressInfo &ref)
{
DecompressInfo info = ref;
BaseStream * ret{};
AuInt8 bits;
bool hasBits;
BaseStream *pRet {};
AuInt8 bits {};
bool bHasBits {};
if (!pReader)
{
SysPushErrorArg("Missing compressed stream pReader");
return nullptr;
}
switch (info.alg)
{
#if defined(_AUHAS_ZSTD)
case ECompressionType::eZSTD:
ret = _new ZSTDInflate(info);
pRet = _new ZSTDInflate(info);
break;
#endif
case ECompressionType::eBZIP2:
#if defined(_AUHAS_BZIP2)
ret = _new BZIPInflate(info);
pRet = _new BZIPInflate(info);
#endif
break;
#if defined(_AUHAS_LZ4)
case ECompressionType::eLZ4:
ret = _new LZ4Inflate(info);
pRet = _new LZ4Inflate(info);
break;
#endif
#if defined(_AUHAS_ZLIB)
@ -57,34 +63,34 @@ namespace Aurora::Compression
case ECompressionType::eZip:
case ECompressionType::eGZip:
hasBits = CompressionLevelFromExternalApi(info, bits);
if (!hasBits && info.alg != ECompressionType::eZip)
bHasBits = CompressionLevelFromExternalApi(info, bits);
if (!bHasBits && info.alg != ECompressionType::eZip)
{
return {};
}
ret = _new ZIPInflate(info, hasBits, bits);
pRet = _new ZIPInflate(info, bHasBits, bits);
break;
#endif
default:
ret = nullptr;
pRet = nullptr;
break;
}
if (ret)
if (pRet)
{
if (!ret->Init(reader))
if (!pRet->Init(pReader))
{
delete ret;
ret = nullptr;
delete pRet;
pRet = nullptr;
}
}
return ret;
return pRet;
}
AUKN_SYM void DecompressorRelease(ICompressionStream * stream)
AUKN_SYM void DecompressorRelease(ICompressionStream *pStream)
{
AuSafeDelete<BaseStream *>(stream);
AuSafeDelete<BaseStream *>(pStream);
}
}

View File

@ -12,14 +12,14 @@
namespace Aurora::Compression
{
AUKN_SYM bool Compress(const Memory::MemoryViewRead &source, Memory::ByteBuffer &out, int compressionLevel)
AUKN_SYM bool Compress(const Memory::MemoryViewRead &source, Memory::ByteBuffer &out, int uCompressionLevel)
{
if (!AuTryResize(out, source.length))
{
return false;
}
auto ret = ZSTD_compress(out.data(), out.size(), source.ptr, source.length, compressionLevel);
auto ret = ZSTD_compress(out.data(), out.size(), source.ptr, source.length, uCompressionLevel);
if (ZSTD_isError(ret))
{
return false;

View File

@ -16,7 +16,7 @@ namespace Aurora::Compression
{
out = 0;
if (!info.hasWindowbits)
if (!info.bHasWindowbits)
{
if (info.alg == ECompressionType::eGZip)
{
@ -33,38 +33,38 @@ namespace Aurora::Compression
}
}
if (info.windowBits < 0)
if (info.uWindowBits < 0)
{
return {};
}
if (info.windowBits > 15)
if (info.uWindowBits > 15)
{
return {};
}
if (info.alg == ECompressionType::eGZip)
{
out = info.windowBits | 16;
out = info.uWindowBits | 16;
}
else if (info.alg == ECompressionType::eDeflate)
{
out = 0 - info.windowBits;
out = 0 - info.uWindowBits;
}
else
{
out = info.windowBits;
out = info.uWindowBits;
}
return true;
}
/// * compression type + bits -> internal zlib windowBits
static bool CompressionLevelFromExternalApi(const CompressionInfo &info, AuInt8 &out)
static bool CompressionLevelFromExternalApi(const CompressInfo &info, AuInt8 &out)
{
out = 0;
if (!info.windowBits)
if (!info.uWindowBits)
{
if (info.type == ECompressionType::eGZip)
{
@ -83,15 +83,15 @@ namespace Aurora::Compression
if (info.type == ECompressionType::eGZip)
{
out = info.windowBits | 16;
out = info.uWindowBits | 16;
}
else if (info.type == ECompressionType::eDeflate)
{
out = 0 - info.windowBits;
out = 0 - info.uWindowBits;
}
else
{
out = info.windowBits;
out = info.uWindowBits;
}
return true;

View File

@ -30,38 +30,38 @@ static const char *BShitToString(int error)
namespace Aurora::Compression
{
struct BZIPDeflate : public BaseStream
struct BZIPDeflate : BaseStream
{
CompressionInfo meta;
CompressInfo meta;
BZIPDeflate(const CompressionInfo &meta) : meta(meta), BaseStream(meta.internalStreamSize)
BZIPDeflate(const CompressInfo &meta) : meta(meta), BaseStream(meta.uInternalStreamSize)
{}
~BZIPDeflate()
{
if (this->init_)
if (this->bInit_)
{
BZ2_bzCompressEnd(&this->ctx_);
}
}
bool Init(const AuSPtr<IO::IStreamReader> &reader) override
bool Init(const AuSPtr<IO::IStreamReader> &pReader) override
{
this->reader_ = reader;
this->pReader_ = pReader;
auto ret = BZ2_bzCompressInit(&this->ctx_, meta.compressionLevel, 0, 0);
if (!this->IsValid())
{
SysPushErrorMem();
return false;
}
auto ret = BZ2_bzCompressInit(&this->ctx_, meta.uCompressionLevel, 0, 0);
if (ret < Z_OK)
{
SysPushErrorMem("Error: {}", BShitToString(ret));
return false;
}
this->init_ = true;
if (!this->_outbuffer)
{
SysPushErrorMem();
return false;
}
this->bInit_ = true;
this->SetArray(this->din_);
return true;
@ -70,9 +70,15 @@ namespace Aurora::Compression
AuStreamReadWrittenPair_t Ingest_s(AuUInt32 input) override
{
AuUInt32 done {}, read {};
if (!this->pReader_)
{
return {};
}
while (read < input)
{
read += IngestForInPointer<char, uInt>(this->reader_, this->ctx_.next_in, this->ctx_.avail_in, input - read);
read += IngestForInPointer<char, uInt>(this->pReader_, this->ctx_.next_in, this->ctx_.avail_in, input - read);
if (!this->ctx_.avail_in)
{
@ -88,6 +94,7 @@ namespace Aurora::Compression
if (ret < Z_OK)
{
SysPushErrorIO("Error: {}", BShitToString(ret));
this->pReader_.reset();
return AuMakePair(read, 0);
}
@ -97,6 +104,8 @@ namespace Aurora::Compression
if (!Write(reinterpret_cast<const AuUInt8 *>(this->dout_),
have))
{
this->pReader_.reset();
SysPushErrorIO("Memory Error");
return AuMakePair(read, 0);
}
@ -119,6 +128,11 @@ namespace Aurora::Compression
bool RunFlush(int type)
{
if (!this->pReader_)
{
return {};
}
if (!this->ctx_.avail_in)
{
do
@ -130,6 +144,7 @@ namespace Aurora::Compression
if (ret < Z_OK)
{
SysPushErrorIO("Error: {}", BShitToString(ret));
this->pReader_.reset();
return false;
}
@ -138,6 +153,8 @@ namespace Aurora::Compression
if (!Write(reinterpret_cast<const AuUInt8*>(this->dout_),
have))
{
this->pReader_.reset();
SysPushErrorIO("Memory Error");
return false;
}
@ -156,6 +173,7 @@ namespace Aurora::Compression
if (ret < Z_OK)
{
SysPushErrorIO("Error: {}", BShitToString(ret));
this->pReader_.reset();
return false;
}
@ -164,6 +182,8 @@ namespace Aurora::Compression
if (!Write(reinterpret_cast<const AuUInt8 *>(this->dout_),
have))
{
this->pReader_.reset();
SysPushErrorIO("Memory Error");
return false;
}
@ -175,11 +195,10 @@ namespace Aurora::Compression
}
private:
AuSPtr<IO::IStreamReader> reader_;
AuSPtr<IO::IStreamReader> pReader_;
bz_stream ctx_ {};
bool init_ {};
bool bInit_ {};
char dout_[kChunkSize];
bool userBound_ {};
char din_[kChunkSize];
};
}

View File

@ -30,24 +30,30 @@ static const char *BShitToString(int error)
namespace Aurora::Compression
{
struct BZIPInflate : public BaseStream
struct BZIPInflate : BaseStream
{
DecompressInfo meta;
BZIPInflate(const DecompressInfo &meta) : meta(meta), BaseStream(meta.internalStreamSize)
BZIPInflate(const DecompressInfo &meta) : meta(meta), BaseStream(meta.uInternalStreamSize)
{}
~BZIPInflate()
{
if (this->init_)
if (this->bInit_)
{
BZ2_bzDecompressEnd(&this->ctx_);
}
}
bool Init(const AuSPtr<IO::IStreamReader> &reader) override
bool Init(const AuSPtr<IO::IStreamReader> &pReader) override
{
this->reader_ = reader;
this->pReader_ = pReader;
if (!this->IsValid())
{
SysPushErrorMem();
return false;
}
auto ret = BZ2_bzDecompressInit(&this->ctx_, 0, 0);
if (ret < Z_OK)
@ -55,13 +61,8 @@ namespace Aurora::Compression
SysPushErrorMem("Error: {}", BShitToString(ret));
return false;
}
this->init_ = true;
if (!this->_outbuffer)
{
SysPushErrorMem();
return false;
}
this->bInit_ = true;
this->SetArray(this->din_);
return true;
@ -70,9 +71,15 @@ namespace Aurora::Compression
AuStreamReadWrittenPair_t Ingest_s(AuUInt32 input) override
{
AuUInt32 done {}, read {};
if (!this->pReader_)
{
return {};
}
while (read < input)
{
read += IngestForInPointer<char, uInt>(this->reader_, this->ctx_.next_in, this->ctx_.avail_in, input - read);
read += IngestForInPointer<char, uInt>(this->pReader_, this->ctx_.next_in, this->ctx_.avail_in, input - read);
if (!this->ctx_.avail_in)
{
@ -88,6 +95,7 @@ namespace Aurora::Compression
if (ret < Z_OK)
{
SysPushErrorIO("Error: {}", BShitToString(ret));
this->pReader_.reset();
return AuMakePair(read, 0);
}
@ -97,6 +105,8 @@ namespace Aurora::Compression
if (!Write(reinterpret_cast<const AuUInt8 *>(this->dout_),
have))
{
SysPushErrorIO("Memory Error");
this->pReader_.reset();
return AuMakePair(read, 0);
}
@ -108,11 +118,10 @@ namespace Aurora::Compression
}
private:
AuSPtr<IO::IStreamReader> reader_;
AuSPtr<IO::IStreamReader> pReader_;
bz_stream ctx_ {};
bool init_ {};
bool bInit_ {};
char dout_[kChunkSize];
bool userBound_ {};
char din_[kChunkSize];
};
}

View File

@ -11,12 +11,12 @@
namespace Aurora::Compression
{
struct ZIPDeflate : public BaseStream
struct ZIPDeflate : BaseStream
{
CompressionInfo meta;
CompressInfo meta;
AuInt8 bits_;
ZIPDeflate(const CompressionInfo &meta, AuInt8 bits) : meta(meta), BaseStream(meta.internalStreamSize), bits_(bits)
ZIPDeflate(const CompressInfo &meta, AuInt8 bits) : meta(meta), BaseStream(meta.uInternalStreamSize), bits_(bits)
{}
~ZIPDeflate()
@ -27,13 +27,19 @@ namespace Aurora::Compression
}
}
bool Init(const AuSPtr<IO::IStreamReader> &reader) override
bool Init(const AuSPtr<IO::IStreamReader> &pReader) override
{
this->reader_ = reader;
this->pReader_ = pReader;
if (!this->IsValid())
{
SysPushErrorMem();
return false;
}
this->ctx_.next_in = this->din_;
auto ret = deflateInit2(&this->ctx_, meta.compressionLevel, Z_DEFLATED, this->bits_, 8, Z_DEFAULT_STRATEGY);
auto ret = deflateInit2(&this->ctx_, meta.uCompressionLevel, Z_DEFLATED, this->bits_, 8, Z_DEFAULT_STRATEGY);
if (ret < Z_OK)
{
SysPushErrorMem("Error: {}", ret);
@ -41,12 +47,6 @@ namespace Aurora::Compression
}
this->init_ = true;
if (!this->_outbuffer)
{
SysPushErrorMem();
return false;
}
this->SetArray(this->din_);
return true;
}
@ -55,9 +55,14 @@ namespace Aurora::Compression
{
AuUInt32 done {}, read {};
if (!this->pReader_)
{
return {};
}
while (read < input)
{
read += IngestForInPointer<Bytef, uInt>(this->reader_, this->ctx_.next_in, this->ctx_.avail_in, input - read);
read += IngestForInPointer<Bytef, uInt>(this->pReader_, this->ctx_.next_in, this->ctx_.avail_in, input - read);
if (!this->ctx_.avail_in)
{
@ -78,6 +83,7 @@ namespace Aurora::Compression
if (ret < Z_OK)
{
SysPushErrorIO("Error: {}", zError(ret));
this->pReader_.reset();
return AuMakePair(read, 0);
}
@ -87,6 +93,8 @@ namespace Aurora::Compression
if (!Write(reinterpret_cast<const AuUInt8 *>(this->dout_),
have))
{
this->pReader_.reset();
SysPushErrorIO("Memory Error");
return AuMakePair(read, 0);
}
@ -109,6 +117,11 @@ namespace Aurora::Compression
bool RunFlush(int type)
{
if (!this->pReader_)
{
return false;
}
if (!this->ctx_.avail_in)
{
do
@ -120,6 +133,7 @@ namespace Aurora::Compression
if (ret < Z_OK)
{
SysPushErrorIO("Error: {}", zError(ret));
this->pReader_.reset();
return false;
}
@ -128,6 +142,8 @@ namespace Aurora::Compression
if (!Write(reinterpret_cast<const AuUInt8*>(this->dout_),
have))
{
this->pReader_.reset();
SysPushErrorIO("Memory Error");
return false;
}
} while (this->ctx_.avail_out == 0);
@ -146,6 +162,7 @@ namespace Aurora::Compression
if (ret < Z_OK)
{
SysPushErrorIO("Error: {}", zError(ret));
this->pReader_.reset();
return false;
}
@ -154,6 +171,8 @@ namespace Aurora::Compression
if (!Write(reinterpret_cast<const AuUInt8 *>(this->dout_),
have))
{
this->pReader_.reset();
SysPushErrorIO("Memory Error");
return false;
}
}
@ -164,7 +183,7 @@ namespace Aurora::Compression
}
private:
AuSPtr<IO::IStreamReader> reader_;
AuSPtr<IO::IStreamReader> pReader_;
z_stream ctx_ {};
bool init_ {};
unsigned char din_[kChunkSize];

View File

@ -11,11 +11,11 @@
namespace Aurora::Compression
{
struct ZIPInflate : public BaseStream
struct ZIPInflate : BaseStream
{
DecompressInfo meta;
ZIPInflate(const DecompressInfo &meta, bool hasBits, AuInt8 bits) : meta(meta), BaseStream(meta.internalStreamSize), bits_(bits), hasBits_(hasBits)
ZIPInflate(const DecompressInfo &meta, bool hasBits, AuInt8 bits) : meta(meta), BaseStream(meta.uInternalStreamSize), cBits_(bits), bHasBits_(hasBits)
{}
~ZIPInflate()
@ -29,11 +29,17 @@ namespace Aurora::Compression
bool Init(const AuSPtr<IO::IStreamReader> &reader) override
{
int ret;
this->reader_ = reader;
this->pReader_ = reader;
if (this->hasBits_)
if (!this->IsValid())
{
ret = inflateInit2(&this->ctx_, this->bits_);
SysPushErrorMem();
return false;
}
if (this->bHasBits_)
{
ret = inflateInit2(&this->ctx_, this->cBits_);
}
else
{
@ -47,12 +53,6 @@ namespace Aurora::Compression
}
this->init_ = true;
if (!this->_outbuffer)
{
SysPushErrorMem();
return false;
}
this->SetArray(this->din_);
return true;
}
@ -61,9 +61,14 @@ namespace Aurora::Compression
{
AuUInt32 done {}, read {};
if (!this->pReader_)
{
return {};
}
while (read < input)
{
read += IngestForInPointer<Bytef, uInt>(this->reader_, this->ctx_.next_in, this->ctx_.avail_in, input - read);
read += IngestForInPointer<Bytef, uInt>(this->pReader_, this->ctx_.next_in, this->ctx_.avail_in, input - read);
if (!this->ctx_.avail_in)
{
@ -84,6 +89,7 @@ namespace Aurora::Compression
if (ret < Z_OK)
{
SysPushErrorIO("Error: {}", zError(ret));
this->pReader_.reset();
return AuMakePair(read, 0);
}
@ -93,7 +99,9 @@ namespace Aurora::Compression
if (!Write(reinterpret_cast<const AuUInt8 *>(this->dout_),
have))
{
return {};
this->pReader_.reset();
SysPushErrorIO("Memory Error");
return AuMakePair(read, 0);
}
}
@ -104,11 +112,11 @@ namespace Aurora::Compression
}
private:
AuSPtr<IO::IStreamReader> reader_;
AuSPtr<IO::IStreamReader> pReader_;
z_stream ctx_ {};
bool init_ {};
bool hasBits_;
AuInt8 bits_;
bool bHasBits_;
AuInt8 cBits_;
unsigned char din_[kChunkSize];
unsigned char dout_[kChunkSize];
};

View File

@ -12,15 +12,11 @@
namespace Aurora::Compression
{
struct LZ4Deflate : public BaseStream
struct LZ4Deflate : BaseStream
{
CompressionInfo meta;
AuSPtr<char> bufferIn_;
AuSPtr<char> bufferOut_;
char* readPtr_;
AuUInt32 bufferInAvail{};
CompressInfo meta;
LZ4Deflate(const CompressionInfo &meta) : meta(meta), BaseStream(meta.internalStreamSize)
LZ4Deflate(const CompressInfo &meta) : meta(meta), BaseStream(meta.uInternalStreamSize)
{
if (meta.bLZ4AutoFlush)
{
@ -33,9 +29,15 @@ namespace Aurora::Compression
}
bool Init(const AuSPtr<IO::IStreamReader> &reader) override
bool Init(const AuSPtr<IO::IStreamReader> &pReader) override
{
this->reader_ = reader;
this->pReader_ = pReader;
if (!this->IsValid())
{
SysPushErrorMem();
return false;
}
auto err = LZ4F_createCompressionContext(&this->cctxPtr, LZ4F_getVersion());
if (LZ4F_isError(err))
@ -43,27 +45,26 @@ namespace Aurora::Compression
return {};
}
auto bufferSize = meta.internalStreamSize;
auto bufferSize = meta.uInternalStreamSize;
this->bufferIn_ = AuSPtr<char>(new char[bufferSize], AuDefaultDeleter<char[]>());
if (!this->bufferIn_)
this->pBufferIn_ = AuMakeSharedArray<char>(bufferSize);
if (!this->pBufferIn_)
{
return {};
}
this->bufferOut_ = AuSPtr<char>(new char[bufferSize], AuDefaultDeleter<char[]>());
if (!this->bufferOut_)
this->pBufferOut_ = AuMakeSharedArray<char>(bufferSize);
if (!this->pBufferOut_)
{
return {};
}
this->readPtr_ = this->bufferIn_.get();
SetPointer(this->readPtr_, bufferSize);
this->pReadPtr_ = this->pBufferIn_.get();
SetPointer(this->pReadPtr_, bufferSize);
return true;
}
bool AU_NOINLINE BeginLZ4FrameIfNeeded()
bool BeginLZ4FrameIfNeeded()
{
if (bDead)
{
@ -78,7 +79,7 @@ namespace Aurora::Compression
return DoLZ4Start();
}
bool AU_NOINLINE EndLZ4FrameIfNeeded()
bool EndLZ4FrameIfNeeded()
{
if (!this->bHasEncodedFrame)
{
@ -93,22 +94,24 @@ namespace Aurora::Compression
return DoLZ4End();
}
bool AU_NOINLINE DoLZ4Start()
bool DoLZ4Start()
{
this->bytesRemInFrame = 0;
this->bHasFinished = false;
auto written = LZ4F_compressBegin(this->cctxPtr, this->bufferOut_.get(), meta.internalStreamSize, &this->pref);
auto written = LZ4F_compressBegin(this->cctxPtr, this->pBufferOut_.get(), meta.uInternalStreamSize, &this->pref);
if (LZ4F_isError(written))
{
this->bDead = true;
return false;
}
bytesRemInFrame = written;
this->bytesRemInFrame = written;
if (written)
{
if (!Write(this->bufferOut_.get(), written))
if (!Write(this->pBufferOut_.get(), written))
{
this->bDead = true;
return {};
}
}
@ -116,15 +119,15 @@ namespace Aurora::Compression
return true;
}
bool AU_NOINLINE DoLZ4End()
bool DoLZ4End()
{
if (!this->bufferOut_)
if (!this->pBufferOut_)
{
return false;
}
auto startPtr = this->bufferOut_.get() + this->bytesRemInFrame;
AuUInt32 bufferedBytes = LZ4F_compressEnd(cctxPtr, startPtr, meta.internalStreamSize - bytesRemInFrame, &options);
auto startPtr = this->pBufferOut_.get() + this->bytesRemInFrame;
AuUInt32 bufferedBytes = LZ4F_compressEnd(cctxPtr, startPtr, meta.uInternalStreamSize - bytesRemInFrame, &options);
if (LZ4F_isError(bufferedBytes))
{
this->bDead = true;
@ -138,6 +141,7 @@ namespace Aurora::Compression
{
if (!Write(startPtr, bufferedBytes))
{
this->bDead = true;
return {};
}
}
@ -157,22 +161,22 @@ namespace Aurora::Compression
return {};
}
auto bufferSize = meta.internalStreamSize;
auto bufferSize = meta.uInternalStreamSize;
while (inputStat < input)
{
inputStat += IngestForInPointer<char, uInt>(this->reader_, this->readPtr_, this->bufferInAvail, input - inputStat);
inputStat += IngestForInPointer<char, uInt>(this->pReader_, this->pReadPtr_, this->uBufferInAvail_, input - inputStat);
if (!this->bufferInAvail)
if (!this->uBufferInAvail_)
{
return { inputStat, (startLen - bytesRemInFrame) };
}
size_t frameSPtr = this->bufferInAvail;
size_t frameSPtr = this->uBufferInAvail_;
size_t frameS2Ptr = bufferSize - bytesRemInFrame;
auto startPtr = this->bufferOut_.get() + bytesRemInFrame;
auto temp = LZ4F_compressUpdate(this->cctxPtr, startPtr, frameS2Ptr, this->readPtr_, frameSPtr, &options);
auto startPtr = this->pBufferOut_.get() + bytesRemInFrame;
auto temp = LZ4F_compressUpdate(this->cctxPtr, startPtr, frameS2Ptr, this->pReadPtr_, frameSPtr, &options);
if (LZ4F_isError(temp))
{
SysPushErrorGeneric("LZ4 internal stream size was too small. ingested too much data. must reset stream now");
@ -182,13 +186,14 @@ namespace Aurora::Compression
bytesRemInFrame += temp;
this->readPtr_ += this->bufferInAvail;
this->bufferInAvail = 0;
this->pReadPtr_ += this->uBufferInAvail_;
this->uBufferInAvail_ = 0;
if (temp)
{
if (!Write(startPtr, temp))
{
this->bDead = true;
return {};
}
}
@ -211,11 +216,15 @@ namespace Aurora::Compression
private:
AuSPtr<char> pBufferIn_;
AuSPtr<char> pBufferOut_;
char *pReadPtr_;
AuUInt32 uBufferInAvail_ {};
bool bHasEncodedFrame{};
bool bHasFinished{};
bool bDead{};
size_t bytesRemInFrame{};
AuSPtr<IO::IStreamReader> reader_;
AuSPtr<IO::IStreamReader> pReader_;
LZ4F_cctx* cctxPtr;
LZ4F_preferences_t pref{};
LZ4F_compressOptions_t options{};

View File

@ -12,18 +12,11 @@
namespace Aurora::Compression
{
class LZ4Inflate : public BaseStream
struct LZ4Inflate : BaseStream
{
AuSPtr<char> bufferIn_;
AuSPtr<char> bufferOut_;
char *readPtr_;
AuUInt32 bufferInAvail {};
public:
DecompressInfo meta;
LZ4Inflate(const DecompressInfo &meta) : meta(meta), BaseStream(meta.internalStreamSize)
LZ4Inflate(const DecompressInfo &meta) : meta(meta), BaseStream(meta.uInternalStreamSize)
{}
~LZ4Inflate()
@ -34,9 +27,15 @@ namespace Aurora::Compression
}
}
bool Init(const AuSPtr<IO::IStreamReader> &reader) override
bool Init(const AuSPtr<IO::IStreamReader> &pReader) override
{
this->reader_ = reader;
this->pReader_ = pReader;
if (!this->IsValid())
{
SysPushErrorMem();
return false;
}
auto err = LZ4F_createDecompressionContext(&this->lz4Stream_, LZ4F_getVersion());
if (LZ4F_isError(err))
@ -44,23 +43,23 @@ namespace Aurora::Compression
return {};
}
auto bufferSize = meta.internalStreamSize;
auto bufferSize = meta.uInternalStreamSize;
this->bufferIn_ = AuSPtr<char>(new char[bufferSize], AuDefaultDeleter<char[]>());
this->pBufferIn_ = AuSPtr<char>(new char[bufferSize], AuDefaultDeleter<char[]>());
if (!this->bufferIn_)
if (!this->pBufferIn_)
{
return {};
}
this->bufferOut_ = AuSPtr<char>(new char[bufferSize], AuDefaultDeleter<char[]>());
if (!this->bufferOut_)
this->pBufferOut_ = AuSPtr<char>(new char[bufferSize], AuDefaultDeleter<char[]>());
if (!this->pBufferOut_)
{
return {};
}
this->readPtr_ = this->bufferIn_.get();
SetPointer(this->readPtr_, bufferSize);
this->pReadPtr_ = this->pBufferIn_.get();
SetPointer(this->pReadPtr_, bufferSize);
return true;
}
@ -71,13 +70,13 @@ namespace Aurora::Compression
size_t bytesRemInFrame {};
LZ4F_decompressOptions_t opts {};
auto bufferSize = meta.internalStreamSize;
auto bufferSize = meta.uInternalStreamSize;
while (inputStat < input)
{
inputStat += IngestForInPointer<char, uInt>(this->reader_, this->readPtr_, this->bufferInAvail, input - inputStat);
inputStat += IngestForInPointer<char, uInt>(this->pReader_, this->pReadPtr_, this->uBufferInAvail_, input - inputStat);
if (!this->bufferInAvail)
if (!this->uBufferInAvail_)
{
return {inputStat, outputStat};
}
@ -85,27 +84,27 @@ namespace Aurora::Compression
auto frameSize = bytesRemInFrame ? bytesRemInFrame : LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH;
frameSize = LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH;
if (this->bufferInAvail < frameSize)
if (this->uBufferInAvail_ < frameSize)
{
return {inputStat, outputStat};
}
size_t frameSPtr = this->bufferInAvail;
size_t frameSPtr = this->uBufferInAvail_;
size_t frameS2Ptr = bufferSize;
bytesRemInFrame = LZ4F_decompress(this->lz4Stream_, this->bufferOut_.get(), &frameS2Ptr, this->readPtr_, &frameSPtr, &opts);
bytesRemInFrame = LZ4F_decompress(this->lz4Stream_, this->pBufferOut_.get(), &frameS2Ptr, this->pReadPtr_, &frameSPtr, &opts);
if (LZ4F_isError(bytesRemInFrame))
{
return {};
}
this->readPtr_ += frameSPtr;
this->pReadPtr_ += frameSPtr;
outputStat += bytesRemInFrame;
this->bufferInAvail -= frameSPtr;
this->uBufferInAvail_ -= frameSPtr;
if (frameS2Ptr)
{
if (!Write(this->bufferOut_.get(), frameS2Ptr))
if (!Write(this->pBufferOut_.get(), frameS2Ptr))
{
return {};
}
@ -118,7 +117,11 @@ namespace Aurora::Compression
}
private:
AuSPtr<IO::IStreamReader> reader_;
AuSPtr<IO::IStreamReader> pReader_;
LZ4F_dctx* lz4Stream_ {};
AuSPtr<char> pBufferIn_;
AuSPtr<char> pBufferOut_;
char *pReadPtr_;
AuUInt32 uBufferInAvail_ {};
};
}

View File

@ -11,26 +11,32 @@
namespace Aurora::Compression
{
struct ZSTDDeflate : public BaseStream
struct ZSTDDeflate : BaseStream
{
CompressionInfo meta;
CompressInfo meta;
ZSTDDeflate(const CompressionInfo &meta) : meta(meta), BaseStream(meta.internalStreamSize)
ZSTDDeflate(const CompressInfo &meta) : meta(meta), BaseStream(meta.uInternalStreamSize)
{}
~ZSTDDeflate()
{
if (auto dctx = AuExchange(cctx_, {}))
if (auto cctx = AuExchange(this->cctx_, {}))
{
ZSTD_freeCCtx(dctx);
ZSTD_freeCCtx(cctx);
}
}
bool Init(const AuSPtr<IO::IStreamReader> &reader) override
bool Init(const AuSPtr<IO::IStreamReader> &pReader) override
{
size_t ret;
AuUInt uRet;
this->reader_ = reader;
if (!this->IsValid())
{
SysPushErrorMem();
return false;
}
this->pReader_ = pReader;
this->cctx_ = ZSTD_createCCtx();
if (!this->cctx_)
@ -38,65 +44,65 @@ namespace Aurora::Compression
SysPushErrorGen("Couldn't create compressor");
}
ret = ZSTD_CCtx_setParameter(this->cctx_, ZSTD_c_compressionLevel, meta.compressionLevel);
if (ZSTD_isError(ret))
uRet = ZSTD_CCtx_setParameter(this->cctx_, ZSTD_c_compressionLevel, meta.uCompressionLevel);
if (ZSTD_isError(uRet))
{
SysPushErrorGen("Invalid compression level");
return false;
}
ret = ZSTD_CCtx_setParameter(this->cctx_, ZSTD_c_checksumFlag, 1);
if (ZSTD_isError(ret))
uRet = ZSTD_CCtx_setParameter(this->cctx_, ZSTD_c_checksumFlag, 1);
if (ZSTD_isError(uRet))
{
SysPushErrorGen("Invalid option");
return false;
}
ret = ZSTD_CCtx_setParameter(this->cctx_, ZSTD_c_nbWorkers, AuMax(meta.threads, AuUInt8(1u)));
if (ZSTD_isError(ret))
uRet = ZSTD_CCtx_setParameter(this->cctx_, ZSTD_c_nbWorkers, AuMax(meta.uThreads, AuUInt8(1u)));
if (ZSTD_isError(uRet))
{
SysPushErrorGen();
return false;
}
if (!this->_outbuffer)
{
SysPushErrorMem();
return false;
}
this->curPtr_ = this->din_;
this->availIn_ = 0;
this->pIterator_ = this->din_;
this->uAvailableIn_ = 0;
SetArray(this->din_);
return true;
}
AuStreamReadWrittenPair_t Ingest_s(AuUInt32 input) override
{
AuUInt32 length = AuUInt32(ZSTD_DStreamInSize());
AuUInt32 outFrameLength = AuUInt32(ZSTD_DStreamOutSize());
AuUInt32 uLength = AuUInt32(ZSTD_DStreamInSize());
AuUInt32 uOutFrameLength = AuUInt32(ZSTD_DStreamOutSize());
AuUInt32 done {}, read {};
if (!this->pReader_)
{
return {};
}
while (read < input)
{
read += IngestForInPointer<char, AuUInt32>(this->reader_, this->curPtr_, this->availIn_, input - read);
read += IngestForInPointer<char, AuUInt32>(this->pReader_, this->pIterator_, this->uAvailableIn_, input - read);
if (!this->availIn_)
if (!this->uAvailableIn_)
{
return {read, done};
}
this->input_ = ZSTD_inBuffer {this->curPtr_, this->availIn_, 0};
this->input_ = ZSTD_inBuffer {this->pIterator_, this->uAvailableIn_, 0};
while (this->input_.pos < this->input_.size)
{
ZSTD_outBuffer output = {this->dout_, outFrameLength, 0};
ZSTD_outBuffer output = {this->dout_, uOutFrameLength, 0};
auto ret = ZSTD_compressStream(this->cctx_, &output, &this->input_);
if (ZSTD_isError(ret))
auto uRet = ZSTD_compressStream(this->cctx_, &output, &this->input_);
if (ZSTD_isError(uRet))
{
SysPushErrorIO("Compression error: {}", ZSTD_getErrorName(ret));
this->availIn_ -= AuUInt32(output.pos);
SysPushErrorIO("Compression error: {}", ZSTD_getErrorName(uRet));
this->uAvailableIn_ -= AuUInt32(output.pos);
this->pReader_.reset();
return AuMakePair(read, 0);
}
@ -110,11 +116,12 @@ namespace Aurora::Compression
if (!Write(reinterpret_cast<const AuUInt8 *>(this->dout_),
AuUInt32(output.pos)))
{
this->pReader_.reset();
return AuMakePair(read, 0);
}
}
this->availIn_ -= AuUInt32(this->input_.pos);
this->uAvailableIn_ -= AuUInt32(this->input_.pos);
}
return {read, done};
@ -132,65 +139,72 @@ namespace Aurora::Compression
bool RunFlush(ZSTD_EndDirective type)
{
AuUInt32 length = AuUInt32(ZSTD_DStreamInSize());
AuUInt32 outFrameLength = AuUInt32(ZSTD_DStreamOutSize());
if (!this->availIn_)
if (!this->pReader_)
{
ZSTD_outBuffer output = { this->dout_, outFrameLength, 0 };
return false;
}
AuUInt32 uLength = AuUInt32(ZSTD_DStreamInSize());
AuUInt32 uOutFrameLength = AuUInt32(ZSTD_DStreamOutSize());
if (!this->uAvailableIn_)
{
ZSTD_outBuffer output = { this->dout_, uOutFrameLength, 0 };
ZSTD_inBuffer input = { NULL, 0, 0 };
auto ret = ZSTD_compressStream2(this->cctx_, &output, &input, type);
if (ZSTD_isError(ret))
auto uRet = ZSTD_compressStream2(this->cctx_, &output, &input, type);
if (ZSTD_isError(uRet))
{
SysPushErrorIO("Compression error: {}", ZSTD_getErrorName(ret));
this->availIn_ -= AuUInt32(output.pos);
SysPushErrorIO("Compression error: {}", ZSTD_getErrorName(uRet));
this->uAvailableIn_ -= AuUInt32(output.pos);
return {};
}
if (!Write(reinterpret_cast<const AuUInt8*>(output.dst),
AuUInt32(output.pos)))
{
this->pReader_.reset();
return false;
}
return true;
}
this->input_ = ZSTD_inBuffer {this->curPtr_, this->availIn_, 0};
this->input_ = ZSTD_inBuffer {this->pIterator_, this->uAvailableIn_, 0};
while (this->input_.pos < this->input_.size)
{
ZSTD_outBuffer output = {this->dout_, outFrameLength, 0};
ZSTD_outBuffer output = {this->dout_, uOutFrameLength, 0};
auto ret = ZSTD_compressStream(this->cctx_, &output, &this->input_);
if (ZSTD_isError(ret))
auto uRet = ZSTD_compressStream(this->cctx_, &output, &this->input_);
if (ZSTD_isError(uRet))
{
SysPushErrorIO("Compression error: {}", ZSTD_getErrorName(ret));
this->availIn_ -= AuUInt32(output.pos);
SysPushErrorIO("Compression error: {}", ZSTD_getErrorName(uRet));
this->uAvailableIn_ -= AuUInt32(output.pos);
return {};
}
if (!Write(reinterpret_cast<const AuUInt8 *>(this->dout_),
AuUInt32(output.pos)))
{
this->pReader_.reset();
return false;
}
}
this->availIn_ -= AuUInt32(this->input_.pos);
this->uAvailableIn_ -= AuUInt32(this->input_.pos);
return true;
}
private:
AuSPtr<IO::IStreamReader> reader_;
AuSPtr<IO::IStreamReader> pReader_;
ZSTD_CCtx *cctx_ {};
char din_[ZSTD_BLOCKSIZE_MAX];
char dout_[ZSTD_BLOCKSIZE_MAX + 3 /*ZSTD_BLOCKHEADERSIZE*/];
char *curPtr_ {};
AuUInt32 availIn_ {};
char *pIterator_ {};
AuUInt32 uAvailableIn_ {};
ZSTD_inBuffer input_;
};
}

View File

@ -11,70 +11,77 @@
namespace Aurora::Compression
{
struct ZSTDInflate : public BaseStream
struct ZSTDInflate : BaseStream
{
DecompressInfo meta;
ZSTDInflate(const DecompressInfo &meta) : meta(meta), BaseStream(meta.internalStreamSize)
ZSTDInflate(const DecompressInfo &meta) : meta(meta), BaseStream(meta.uInternalStreamSize)
{}
~ZSTDInflate()
{
if (auto dctx = AuExchange(dctx_, {}))
if (auto dctx = AuExchange(this->dctx_, {}))
{
ZSTD_freeDCtx(dctx);
}
}
bool Init(const AuSPtr<IO::IStreamReader> &reader) override
bool Init(const AuSPtr<IO::IStreamReader> &pReader) override
{
this->reader_ = reader;
this->pReader_ = pReader;
this->dctx_ = ZSTD_createDCtx();
if (!this->IsValid())
{
SysPushErrorMem();
return false;
}
if (!this->dctx_)
{
SysPushErrorGen("Couldn't create decompressor");
return false;
}
if (!this->_outbuffer)
{
SysPushErrorMem();
return false;
}
this->curPtr_ = this->din_;
this->availIn_ = 0;
this->pIterator_ = this->din_;
this->uAvailableIn_ = 0;
SetArray(this->din_);
return true;
}
AuStreamReadWrittenPair_t Ingest_s(AuUInt32 input) override
{
AuUInt32 length = AuUInt32(ZSTD_DStreamInSize());
AuUInt32 outFrameLength = AuUInt32(ZSTD_DStreamOutSize());
AuUInt32 uLength = AuUInt32(ZSTD_DStreamInSize());
AuUInt32 uOutFrameLength = AuUInt32(ZSTD_DStreamOutSize());
AuUInt32 done {}, read {};
if (!this->pReader_)
{
return {};
}
while (read < input)
{
read += IngestForInPointer<char, AuUInt32>(this->reader_, this->curPtr_, this->availIn_, input - read);
read += IngestForInPointer<char, AuUInt32>(this->pReader_, this->pIterator_, this->uAvailableIn_, input - read);
if (!this->availIn_)
if (!this->uAvailableIn_)
{
return {read, done};
}
this->input_ = ZSTD_inBuffer {this->curPtr_, this->availIn_, 0};
this->input_ = ZSTD_inBuffer {this->pIterator_, this->uAvailableIn_, 0};
while (this->input_.pos < this->input_.size)
{
ZSTD_outBuffer output = {this->dout_, outFrameLength, 0};
ZSTD_outBuffer output = {this->dout_, uOutFrameLength, 0};
auto ret = ZSTD_decompressStream(this->dctx_, &output, &this->input_);
if (ZSTD_isError(ret))
{
SysPushErrorIO("Compression error: {}", ZSTD_getErrorName(ret));
this->availIn_ -= AuUInt32(output.pos);
this->uAvailableIn_ -= AuUInt32(output.pos);
this->pReader_.reset();
return AuMakePair(read, 0);
}
@ -83,11 +90,12 @@ namespace Aurora::Compression
if (!Write(reinterpret_cast<const AuUInt8 *>(output.dst),
AuUInt32(output.pos)))
{
this->pReader_.reset();
return AuMakePair(read, 0);
}
}
this->availIn_ -= AuUInt32(this->input_.pos);
this->uAvailableIn_ -= AuUInt32(this->input_.pos);
}
return {read, done};
@ -95,12 +103,12 @@ namespace Aurora::Compression
private:
AuSPtr<IO::IStreamReader> reader_;
AuSPtr<IO::IStreamReader> pReader_;
ZSTD_DCtx *dctx_ {};
char din_[ZSTD_BLOCKSIZE_MAX + 3 /*ZSTD_BLOCKHEADERSIZE*/];
char dout_[ZSTD_BLOCKSIZE_MAX];
char *curPtr_ {};
AuUInt32 availIn_ {};
char *pIterator_ {};
AuUInt32 uAvailableIn_ {};
ZSTD_inBuffer input_;
};
}

View File

@ -21,8 +21,8 @@ namespace Aurora::Compression
inline AuUInt32 IngestForInPointer(const AuSPtr<IO::IStreamReader> &reader, T *&in, Z &inAlreadyAvailable, AuUInt32 amount);
private:
AuUInt8 *internalInBuffer_;
AuUInt32 internalInLength_;
AuUInt8 *internalInBuffer_ {};
AuUInt32 internalInLength_ {};
};
}

View File

@ -109,7 +109,7 @@ namespace Aurora::Compression
return true;
}
static bool CompressZSTD(const CompressionPipe &stream, const CompressionInfo &info)
static bool CompressZSTD(const CompressionPipe &stream, const CompressInfo &info)
{
Memory::ByteBuffer inflatedBuffer;
Memory::ByteBuffer deflatedBuffer;
@ -148,7 +148,7 @@ namespace Aurora::Compression
return false;
}
ret = ZSTD_CCtx_setParameter(cctx, ZSTD_c_compressionLevel, info.compressionLevel);
ret = ZSTD_CCtx_setParameter(cctx, ZSTD_c_compressionLevel, info.uCompressionLevel);
if (ZSTD_isError(ret))
{
SysPushErrorGen("Invalid compression level");
@ -425,7 +425,7 @@ namespace Aurora::Compression
return true;
}
static bool CompressBZip2(const CompressionPipe &stream, const CompressionInfo &info)
static bool CompressBZip2(const CompressionPipe &stream, const CompressInfo &info)
{
#if defined(_AUHAS_BZIP2)
int ret, flush;
@ -443,7 +443,7 @@ namespace Aurora::Compression
return false;
}
ret = BZ2_bzCompressInit(&strm, info.compressionLevel, 0, 0);
ret = BZ2_bzCompressInit(&strm, info.uCompressionLevel, 0, 0);
if (ret < BZ_OK)
{
SysPushErrorIO("Error: {}", ret);
@ -608,7 +608,7 @@ namespace Aurora::Compression
#endif
}
static bool CompressLZ4(const CompressionPipe &stream, const CompressionInfo &info)
static bool CompressLZ4(const CompressionPipe &stream, const CompressInfo &info)
{
#if defined(_AUHAS_LZ4)
bool ret;
@ -619,10 +619,10 @@ namespace Aurora::Compression
char header[512];
ret = true;
pref.compressionLevel = info.compressionLevel;
pref.compressionLevel = info.uCompressionLevel;
pref.autoFlush = true;
auto maxFrameSize = info.lz4BlockSize ? info.lz4BlockSize : 64 * 1024;
auto maxFrameSize = info.uLz4BlockSize ? info.uLz4BlockSize : 64 * 1024;
auto buffer = AuSPtr<char>(new char[maxFrameSize], AuDefaultDeleter<char[]>());
auto maxOut = LZ4F_compressBound(maxFrameSize, &pref);
auto outBuffer = AuSPtr<char>(new char[maxOut], AuDefaultDeleter<char[]>());;
@ -812,9 +812,9 @@ namespace Aurora::Compression
#endif
}
AUKN_SYM bool Compress(const CompressionPipe &stream, const CompressionInfo &info)
AUKN_SYM bool Compress(const CompressionPipe &stream, const CompressInfo &info)
{
CompressionInfo meta = info;
CompressInfo meta = info;
AuInt8 bits;
if (!stream.pReadPipe)
@ -838,7 +838,7 @@ namespace Aurora::Compression
return {};
}
return CompressZLib(stream, info.compressionLevel, bits);
return CompressZLib(stream, info.uCompressionLevel, bits);
}
case ECompressionType::eZSTD:
return CompressZSTD(stream, info);
@ -886,7 +886,7 @@ namespace Aurora::Compression
case ECompressionType::eBZIP2:
return DecompressBZip2(pipe);
case ECompressionType::eLZ4:
return DecompressLZ4(pipe, meta.internalStreamSize / 2);
return DecompressLZ4(pipe, meta.uInternalStreamSize / 2);
//case ECompressionType::eLZMA:
// return DecompressLZMA(pipe);
default:

View File

@ -0,0 +1,104 @@
/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: BCrypt.cpp
Date: 2022-9-15
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include "BCrypt.hpp"
extern "C"
{
#include "crypt_blowfish.h"
}
namespace Aurora::Crypto::BCrypt
{
static const int kMinBCryptRounds = 10;
AUKN_SYM int GetForcedMinRounds()
{
return kMinBCryptRounds;
}
AUKN_SYM AuString GenSalt(int rounds)
{
char seed[16];
char cryptLength[31];
AuRng::RngFillArray<false>(seed);
rounds = AuMin(rounds, 31);
rounds = AuMax(rounds, kMinBCryptRounds);
auto ptr = _crypt_gensalt_blowfish_rn("$2a$",
rounds,
seed,
16,
cryptLength,
AuArraySize(cryptLength));
SysAssert(ptr, "?");
return ptr;
}
AUKN_SYM AuString HashPW(const AuString &password, const AuString &salt)
{
return HashPWEx({ password.c_str(), password.size() + 1 }, salt);
}
AUKN_SYM AuString HashPWEx(const Memory::MemoryViewRead &password, const AuString &salt)
{
if (password.length > 72)
{
SysPushErrorCrypt("BCrypt password cannot be greater than 72 characters");
return {};
}
char cryptBuffer[62] { 0 };
char *pRet;
if (!(pRet = crypt_rn(password.Begin<char>(),
password.length,
salt.c_str(),
cryptBuffer,
AuArraySize(cryptBuffer))))
{
SysPushErrorCrypto("bcrypt failed");
return {};
}
return pRet;
}
AUKN_SYM bool CheckPassword(const AuString &password, const AuString &hashedPassword)
{
return CheckPasswordEx({ password.c_str(), password.size() + 1 }, hashedPassword);
}
AUKN_SYM bool CheckPasswordEx(const Memory::MemoryViewRead &password, const AuString &hashedPassword)
{
if (password.length == 0)
{
return false;
}
if (hashedPassword.empty())
{
return false;
}
char cryptBuffer[62] { 0 };
char *pRet;
if (!(pRet = crypt_rn(password.Begin<char>(),
password.length,
hashedPassword.c_str(),
cryptBuffer,
AuArraySize(cryptBuffer))))
{
SysPushErrorCrypto("bcrypt failed");
return {};
}
// I don't care about safe eval...
return cryptBuffer == hashedPassword;
}
}

View File

@ -0,0 +1,9 @@
/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: BCrypt.cpp
Date: 2022-9-15
Author: Reece
***/
#include <Aurora/Crypto/BCrypt/BCrypt.hpp>

View File

@ -0,0 +1,29 @@
New versions of this package (crypt_blowfish):
http://www.openwall.com/crypt/
A paper on the algorithm that explains its design decisions:
http://www.usenix.org/events/usenix99/provos.html
Unix Seventh Edition Manual, Volume 2: the password scheme (1978):
http://plan9.bell-labs.com/7thEdMan/vol2/password
The Openwall GNU/*/Linux (Owl) tcb suite implementing the alternative
password shadowing scheme. This includes a PAM module which
supersedes pam_unix and uses the password hashing framework provided
with crypt_blowfish when setting new passwords.
http://www.openwall.com/tcb/
pam_passwdqc, a password strength checking and policy enforcement
module for PAM-aware password changing programs:
http://www.openwall.com/passwdqc/
John the Ripper password cracker:
http://www.openwall.com/john/
$Owl: Owl/packages/glibc/crypt_blowfish/LINKS,v 1.4 2005/11/16 13:09:47 solar Exp $

View File

@ -0,0 +1,68 @@
This is an implementation of a password hashing method, provided via the
crypt(3) and a reentrant interface. It is fully compatible with
OpenBSD's bcrypt.c for prefix "$2b$", originally by Niels Provos and
David Mazieres. (Please refer to the included crypt(3) man page for
information on minor compatibility issues for other bcrypt prefixes.)
I've placed this code in the public domain, with fallback to a
permissive license. Please see the comment in crypt_blowfish.c for
more information.
You can use the provided routines in your own packages, or link them
into a C library. I've provided hooks for linking into GNU libc, but
it shouldn't be too hard to get this into another C library. Note
that simply adding this code into your libc is probably not enough to
make your system use the new password hashing algorithm. Changes to
passwd(1), PAM modules, or whatever else your system uses will likely
be needed as well. These are not a part of this package, but see
LINKS for a pointer to our tcb suite.
Instructions on using the routines in one of the two common ways are
given below. It is recommended that you test the routines on your
system before you start. Type "make check" or "make check_threads"
(if you have the POSIX threads library), then "make clean".
1. Using the routines in your programs.
The available interfaces are in ow-crypt.h, and this is the file you
should include. You won't need crypt.h. When linking, add all of the
C files and x86.S (you can compile and link it even on a non-x86, it
will produce no code in this case).
2. Building the routines into GNU C library.
For versions 2.13 and 2.14 (and likely other nearby ones), extract the
library sources as usual. Apply the patch for glibc 2.14 provided in
this package. Enter crypt/ and rename crypt.h to gnu-crypt.h within
that directory. Copy the C sources, header, and assembly (x86.S) files
from this package in there as well (but be sure you don't overwrite the
Makefile). Configure, build, and install the library as usual.
For versions 2.2 to 2.3.6 (and likely also for some newer ones),
extract the library sources and maybe its optional add-ons as usual.
Apply the patch for glibc 2.3.6 provided in this package. Enter
crypt/ and rename crypt.h to gnu-crypt.h within that directory. Copy
the C sources, header, and assembly (x86.S) files from this package in
there as well (but be sure you don't overwrite the Makefile).
Configure, build, and install the library as usual.
For versions 2.1 to 2.1.3, extract the library sources and the crypt
and linuxthreads add-ons as usual. Apply the patch for glibc 2.1.3
provided in this package. Enter crypt/sysdeps/unix/, and rename
crypt.h to gnu-crypt.h within that directory. Copy C sources, header,
and assembly (x86.S) files from this package in there as well (but be
sure you don't overwrite the Makefile). Configure, build, and install
the library as usual.
Programs that want to use the provided interfaces will need to include
crypt.h (but not ow-crypt.h directly). By default, prototypes for the
new routines aren't defined (but the extra functionality of crypt(3)
is indeed available). You need to define _OW_SOURCE to obtain the new
routines as well.
--
Solar Designer <solar at openwall.com>
$Owl: Owl/packages/glibc/crypt_blowfish/README,v 1.10 2014/07/07 15:19:04 solar Exp $

View File

@ -0,0 +1,870 @@
/*
* The crypt_blowfish homepage is:
*
* http://www.openwall.com/crypt/
*
* This code comes from John the Ripper password cracker, with reentrant
* and crypt(3) interfaces added, but optimizations specific to password
* cracking removed.
*
* Written by Solar Designer <solar at openwall.com> in 1998-2014.
* No copyright is claimed, and the software is hereby placed in the public
* domain. In case this attempt to disclaim copyright and place the software
* in the public domain is deemed null and void, then the software is
* Copyright (c) 1998-2014 Solar Designer and it is hereby released to the
* general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*
* It is my intent that you should be able to use this on your system,
* as part of a software package, or anywhere else to improve security,
* ensure compatibility, or for any other purpose. I would appreciate
* it if you give credit where it is due and keep your modifications in
* the public domain as well, but I don't require that in order to let
* you place this code and any modifications you make under a license
* of your choice.
*
* This implementation is fully compatible with OpenBSD's bcrypt.c for prefix
* "$2b$", originally by Niels Provos <provos at citi.umich.edu>, and it uses
* some of his ideas. The password hashing algorithm was designed by David
* Mazieres <dm at lcs.mit.edu>. For information on the level of
* compatibility for bcrypt hash prefixes other than "$2b$", please refer to
* the comments in BF_set_key() below and to the included crypt(3) man page.
*
* There's a paper on the algorithm that explains its design decisions:
*
* http://www.usenix.org/events/usenix99/provos.html
*
* Some of the tricks in BF_ROUND might be inspired by Eric Young's
* Blowfish library (I can't be sure if I would think of something if I
* hadn't seen his code).
*
* -------------------------------------------------------------------------
*
* Notes:
* FIXED: BREAK NULL - 15/09/2022
*
*/
#include <string.h>
#include <errno.h>
#ifndef __set_errno
#define __set_errno(val) errno = (val)
#endif
/* Just to make sure the prototypes match the actual definitions */
#include "crypt_blowfish.h"
#ifdef __i386__
#define BF_ASM 1
#define BF_SCALE 1
#elif defined(__x86_64__) || defined(__alpha__) || defined(__hppa__)
#define BF_ASM 0
#define BF_SCALE 1
#else
#define BF_ASM 0
#define BF_SCALE 0
#endif
typedef unsigned int BF_word;
typedef signed int BF_word_signed;
/* Number of Blowfish rounds, this is also hardcoded into a few places */
#define BF_N 16
typedef BF_word BF_key[BF_N + 2];
typedef struct {
BF_word S[4][0x100];
BF_key P;
} BF_ctx;
/*
* Magic IV for 64 Blowfish encryptions that we do at the end.
* The string is "OrpheanBeholderScryDoubt" on big-endian.
*/
static BF_word BF_magic_w[6] = {
0x4F727068, 0x65616E42, 0x65686F6C,
0x64657253, 0x63727944, 0x6F756274
};
/*
* P-box and S-box tables initialized with digits of Pi.
*/
static BF_ctx BF_init_state = {
{
{
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,
0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,
0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,
0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,
0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,
0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,
0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,
0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,
0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,
0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,
0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,
0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,
0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,
0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,
0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,
0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,
0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,
0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,
0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,
0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
}, {
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,
0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,
0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,
0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,
0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,
0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,
0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,
0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,
0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,
0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,
0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
}, {
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,
0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,
0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,
0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,
0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,
0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,
0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,
0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,
0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,
0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,
0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
}, {
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,
0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,
0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,
0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,
0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,
0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,
0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,
0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,
0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,
0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,
0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,
0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,
0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,
0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,
0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,
0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,
0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,
0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,
0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,
0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,
0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
}
}, {
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
0x9216d5d9, 0x8979fb1b
}
};
static unsigned char BF_itoa64[64 + 1] =
"./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
static unsigned char BF_atoi64[0x60] = {
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 1,
54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 64, 64, 64, 64, 64,
64, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 64, 64, 64, 64, 64,
64, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 64, 64, 64, 64, 64
};
#define BF_safe_atoi64(dst, src) \
{ \
tmp = (unsigned char)(src); \
if ((unsigned int)(tmp -= 0x20) >= 0x60) return -1; \
tmp = BF_atoi64[tmp]; \
if (tmp > 63) return -1; \
(dst) = tmp; \
}
static int BF_decode(BF_word *dst, const char *src, int size)
{
unsigned char *dptr = (unsigned char *)dst;
unsigned char *end = dptr + size;
const unsigned char *sptr = (const unsigned char *)src;
unsigned int tmp, c1, c2, c3, c4;
do {
BF_safe_atoi64(c1, *sptr++);
BF_safe_atoi64(c2, *sptr++);
*dptr++ = (c1 << 2) | ((c2 & 0x30) >> 4);
if (dptr >= end) break;
BF_safe_atoi64(c3, *sptr++);
*dptr++ = ((c2 & 0x0F) << 4) | ((c3 & 0x3C) >> 2);
if (dptr >= end) break;
BF_safe_atoi64(c4, *sptr++);
*dptr++ = ((c3 & 0x03) << 6) | c4;
} while (dptr < end);
return 0;
}
static void BF_encode(char *dst, const BF_word *src, int size)
{
const unsigned char *sptr = (const unsigned char *)src;
const unsigned char *end = sptr + size;
unsigned char *dptr = (unsigned char *)dst;
unsigned int c1, c2;
do {
c1 = *sptr++;
*dptr++ = BF_itoa64[c1 >> 2];
c1 = (c1 & 0x03) << 4;
if (sptr >= end) {
*dptr++ = BF_itoa64[c1];
break;
}
c2 = *sptr++;
c1 |= c2 >> 4;
*dptr++ = BF_itoa64[c1];
c1 = (c2 & 0x0f) << 2;
if (sptr >= end) {
*dptr++ = BF_itoa64[c1];
break;
}
c2 = *sptr++;
c1 |= c2 >> 6;
*dptr++ = BF_itoa64[c1];
*dptr++ = BF_itoa64[c2 & 0x3f];
} while (sptr < end);
}
static void BF_swap(BF_word *x, int count)
{
static int endianness_check = 1;
char *is_little_endian = (char *)&endianness_check;
BF_word tmp;
if (*is_little_endian)
do {
tmp = *x;
tmp = (tmp << 16) | (tmp >> 16);
*x++ = ((tmp & 0x00FF00FF) << 8) | ((tmp >> 8) & 0x00FF00FF);
} while (--count);
}
#if BF_SCALE
/* Architectures which can shift addresses left by 2 bits with no extra cost */
#define BF_ROUND(L, R, N) \
tmp1 = L & 0xFF; \
tmp2 = L >> 8; \
tmp2 &= 0xFF; \
tmp3 = L >> 16; \
tmp3 &= 0xFF; \
tmp4 = L >> 24; \
tmp1 = data.ctx.S[3][tmp1]; \
tmp2 = data.ctx.S[2][tmp2]; \
tmp3 = data.ctx.S[1][tmp3]; \
tmp3 += data.ctx.S[0][tmp4]; \
tmp3 ^= tmp2; \
R ^= data.ctx.P[N + 1]; \
tmp3 += tmp1; \
R ^= tmp3;
#else
/* Architectures with no complicated addressing modes supported */
#define BF_INDEX(S, i) \
(*((BF_word *)(((unsigned char *)S) + (i))))
#define BF_ROUND(L, R, N) \
tmp1 = L & 0xFF; \
tmp1 <<= 2; \
tmp2 = L >> 6; \
tmp2 &= 0x3FC; \
tmp3 = L >> 14; \
tmp3 &= 0x3FC; \
tmp4 = L >> 22; \
tmp4 &= 0x3FC; \
tmp1 = BF_INDEX(data.ctx.S[3], tmp1); \
tmp2 = BF_INDEX(data.ctx.S[2], tmp2); \
tmp3 = BF_INDEX(data.ctx.S[1], tmp3); \
tmp3 += BF_INDEX(data.ctx.S[0], tmp4); \
tmp3 ^= tmp2; \
R ^= data.ctx.P[N + 1]; \
tmp3 += tmp1; \
R ^= tmp3;
#endif
/*
* Encrypt one block, BF_N is hardcoded here.
*/
#define BF_ENCRYPT \
L ^= data.ctx.P[0]; \
BF_ROUND(L, R, 0); \
BF_ROUND(R, L, 1); \
BF_ROUND(L, R, 2); \
BF_ROUND(R, L, 3); \
BF_ROUND(L, R, 4); \
BF_ROUND(R, L, 5); \
BF_ROUND(L, R, 6); \
BF_ROUND(R, L, 7); \
BF_ROUND(L, R, 8); \
BF_ROUND(R, L, 9); \
BF_ROUND(L, R, 10); \
BF_ROUND(R, L, 11); \
BF_ROUND(L, R, 12); \
BF_ROUND(R, L, 13); \
BF_ROUND(L, R, 14); \
BF_ROUND(R, L, 15); \
tmp4 = R; \
R = L; \
L = tmp4 ^ data.ctx.P[BF_N + 1];
#if BF_ASM
#define BF_body() \
_BF_body_r(&data.ctx);
#else
#define BF_body() \
L = R = 0; \
ptr = data.ctx.P; \
do { \
ptr += 2; \
BF_ENCRYPT; \
*(ptr - 2) = L; \
*(ptr - 1) = R; \
} while (ptr < &data.ctx.P[BF_N + 2]); \
\
ptr = data.ctx.S[0]; \
do { \
ptr += 2; \
BF_ENCRYPT; \
*(ptr - 2) = L; \
*(ptr - 1) = R; \
} while (ptr < &data.ctx.S[3][0xFF]);
#endif
static void BF_set_key(const char *key, int inLength, BF_key expanded, BF_key initial,
unsigned char flags)
{
const char *ptr = key;
unsigned int bug, i, j, z;
BF_word safety, sign, diff, tmp[2];
/*
* There was a sign extension bug in older revisions of this function. While
* we would have liked to simply fix the bug and move on, we have to provide
* a backwards compatibility feature (essentially the bug) for some systems and
* a safety measure for some others. The latter is needed because for certain
* multiple inputs to the buggy algorithm there exist easily found inputs to
* the correct algorithm that produce the same hash. Thus, we optionally
* deviate from the correct algorithm just enough to avoid such collisions.
* While the bug itself affected the majority of passwords containing
* characters with the 8th bit set (although only a percentage of those in a
* collision-producing way), the anti-collision safety measure affects
* only a subset of passwords containing the '\xff' character (not even all of
* those passwords, just some of them). This character is not found in valid
* UTF-8 sequences and is rarely used in popular 8-bit character encodings.
* Thus, the safety measure is unlikely to cause much annoyance, and is a
* reasonable tradeoff to use when authenticating against existing hashes that
* are not reliably known to have been computed with the correct algorithm.
*
* We use an approach that tries to minimize side-channel leaks of password
* information - that is, we mostly use fixed-cost bitwise operations instead
* of branches or table lookups. (One conditional branch based on password
* length remains. It is not part of the bug aftermath, though, and is
* difficult and possibly unreasonable to avoid given the use of C strings by
* the caller, which results in similar timing leaks anyway.)
*
* For actual implementation, we set an array index in the variable "bug"
* (0 means no bug, 1 means sign extension bug emulation) and a flag in the
* variable "safety" (bit 16 is set when the safety measure is requested).
* Valid combinations of settings are:
*
* Prefix "$2a$": bug = 0, safety = 0x10000
* Prefix "$2b$": bug = 0, safety = 0
* Prefix "$2x$": bug = 1, safety = 0
* Prefix "$2y$": bug = 0, safety = 0
*/
bug = (unsigned int)flags & 1;
safety = ((BF_word)flags & 2) << 15;
sign = diff = 0;
z = 0;
for (i = 0; i < BF_N + 2; i++) {
tmp[0] = tmp[1] = 0;
for (j = 0; j < 4; j++) {
auto data = key[(z++) % inLength];
tmp[0] <<= 8;
tmp[0] |= (unsigned char)data; /* correct */
tmp[1] <<= 8;
tmp[1] |= (BF_word_signed)(signed char)data; /* bug */
/*
* Sign extension in the first char has no effect - nothing to overwrite yet,
* and those extra 24 bits will be fully shifted out of the 32-bit word. For
* chars 2, 3, 4 in each four-char block, we set bit 7 of "sign" if sign
* extension in tmp[1] occurs. Once this flag is set, it remains set.
*/
if (j)
sign |= tmp[1] & 0x80;
}
diff |= tmp[0] ^ tmp[1]; /* Non-zero on any differences */
expanded[i] = tmp[bug];
initial[i] = BF_init_state.P[i] ^ tmp[bug];
}
/*
* At this point, "diff" is zero iff the correct and buggy algorithms produced
* exactly the same result. If so and if "sign" is non-zero, which indicates
* that there was a non-benign sign extension, this means that we have a
* collision between the correctly computed hash for this password and a set of
* passwords that could be supplied to the buggy algorithm. Our safety measure
* is meant to protect from such many-buggy to one-correct collisions, by
* deviating from the correct algorithm in such cases. Let's check for this.
*/
diff |= diff >> 16; /* still zero iff exact match */
diff &= 0xffff; /* ditto */
diff += 0xffff; /* bit 16 set iff "diff" was non-zero (on non-match) */
sign <<= 9; /* move the non-benign sign extension flag to bit 16 */
sign &= ~diff & safety; /* action needed? */
/*
* If we have determined that we need to deviate from the correct algorithm,
* flip bit 16 in initial expanded key. (The choice of 16 is arbitrary, but
* let's stick to it now. It came out of the approach we used above, and it's
* not any worse than any other choice we could make.)
*
* It is crucial that we don't do the same to the expanded key used in the main
* Eksblowfish loop. By doing it to only one of these two, we deviate from a
* state that could be directly specified by a password to the buggy algorithm
* (and to the fully correct one as well, but that's a side-effect).
*/
initial[0] ^= sign;
}
static const unsigned char flags_by_subtype[26] =
{2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0};
static char *BF_crypt(const char *key, int inLen, const char *setting,
char *output, int size,
BF_word min)
{
#if BF_ASM
extern void _BF_body_r(BF_ctx *ctx);
#endif
struct {
BF_ctx ctx;
BF_key expanded_key;
union {
BF_word salt[4];
BF_word output[6];
} binary;
} data;
BF_word L, R;
BF_word tmp1, tmp2, tmp3, tmp4;
BF_word *ptr;
BF_word count;
int i;
if (size < 7 + 22 + 31 + 1) {
__set_errno(ERANGE);
return NULL;
}
if (setting[0] != '$' ||
setting[1] != '2' ||
setting[2] < 'a' || setting[2] > 'z' ||
!flags_by_subtype[(unsigned int)(unsigned char)setting[2] - 'a'] ||
setting[3] != '$' ||
setting[4] < '0' || setting[4] > '3' ||
setting[5] < '0' || setting[5] > '9' ||
(setting[4] == '3' && setting[5] > '1') ||
setting[6] != '$') {
__set_errno(EINVAL);
return NULL;
}
count = (BF_word)1 << ((setting[4] - '0') * 10 + (setting[5] - '0'));
if (count < min || BF_decode(data.binary.salt, &setting[7], 16)) {
__set_errno(EINVAL);
return NULL;
}
BF_swap(data.binary.salt, 4);
BF_set_key(key, inLen, data.expanded_key, data.ctx.P,
flags_by_subtype[(unsigned int)(unsigned char)setting[2] - 'a']);
memcpy(data.ctx.S, BF_init_state.S, sizeof(data.ctx.S));
L = R = 0;
for (i = 0; i < BF_N + 2; i += 2) {
L ^= data.binary.salt[i & 2];
R ^= data.binary.salt[(i & 2) + 1];
BF_ENCRYPT;
data.ctx.P[i] = L;
data.ctx.P[i + 1] = R;
}
ptr = data.ctx.S[0];
do {
ptr += 4;
L ^= data.binary.salt[(BF_N + 2) & 3];
R ^= data.binary.salt[(BF_N + 3) & 3];
BF_ENCRYPT;
*(ptr - 4) = L;
*(ptr - 3) = R;
L ^= data.binary.salt[(BF_N + 4) & 3];
R ^= data.binary.salt[(BF_N + 5) & 3];
BF_ENCRYPT;
*(ptr - 2) = L;
*(ptr - 1) = R;
} while (ptr < &data.ctx.S[3][0xFF]);
do {
int done;
for (i = 0; i < BF_N + 2; i += 2) {
data.ctx.P[i] ^= data.expanded_key[i];
data.ctx.P[i + 1] ^= data.expanded_key[i + 1];
}
done = 0;
do {
BF_body();
if (done)
break;
done = 1;
tmp1 = data.binary.salt[0];
tmp2 = data.binary.salt[1];
tmp3 = data.binary.salt[2];
tmp4 = data.binary.salt[3];
for (i = 0; i < BF_N; i += 4) {
data.ctx.P[i] ^= tmp1;
data.ctx.P[i + 1] ^= tmp2;
data.ctx.P[i + 2] ^= tmp3;
data.ctx.P[i + 3] ^= tmp4;
}
data.ctx.P[16] ^= tmp1;
data.ctx.P[17] ^= tmp2;
} while (1);
} while (--count);
for (i = 0; i < 6; i += 2) {
L = BF_magic_w[i];
R = BF_magic_w[i + 1];
count = 64;
do {
BF_ENCRYPT;
} while (--count);
data.binary.output[i] = L;
data.binary.output[i + 1] = R;
}
memcpy(output, setting, 7 + 22 - 1);
output[7 + 22 - 1] = BF_itoa64[(int)
BF_atoi64[(int)setting[7 + 22 - 1] - 0x20] & 0x30];
/* This has to be bug-compatible with the original implementation, so
* only encode 23 of the 24 bytes. :-) */
BF_swap(data.binary.output, 6);
BF_encode(&output[7 + 22], data.binary.output, 23);
output[7 + 22 + 31] = '\0';
return output;
}
int _crypt_output_magic(const char *setting, char *output, int size)
{
if (size < 3)
return -1;
output[0] = '*';
output[1] = '0';
output[2] = '\0';
if (setting[0] == '*' && setting[1] == '0')
output[1] = '1';
return 0;
}
/*
* Please preserve the runtime self-test. It serves two purposes at once:
*
* 1. We really can't afford the risk of producing incompatible hashes e.g.
* when there's something like gcc bug 26587 again, whereas an application or
* library integrating this code might not also integrate our external tests or
* it might not run them after every build. Even if it does, the miscompile
* might only occur on the production build, but not on a testing build (such
* as because of different optimization settings). It is painful to recover
* from incorrectly-computed hashes - merely fixing whatever broke is not
* enough. Thus, a proactive measure like this self-test is needed.
*
* 2. We don't want to leave sensitive data from our actual password hash
* computation on the stack or in registers. Previous revisions of the code
* would do explicit cleanups, but simply running the self-test after hash
* computation is more reliable.
*
* The performance cost of this quick self-test is around 0.6% at the "$2a$08"
* setting.
*/
char *_crypt_blowfish_rn(const char *key,
int inLen,
const char *setting,
char *output,
int size)
{
_crypt_output_magic(setting, output, size);
return BF_crypt(key, inLen, setting, output, size, 16);
}
char *_crypt_gensalt_blowfish_rn(const char *prefix,
unsigned long count,
const char *input,
int size,
char *output,
int output_size)
{
if (size < 16 || output_size < 7 + 22 + 1 ||
(count && (count < 4 || count > 31)) ||
prefix[0] != '$' || prefix[1] != '2' ||
(prefix[2] != 'a' && prefix[2] != 'b' && prefix[2] != 'y')) {
if (output_size > 0) output[0] = '\0';
__set_errno((output_size < 7 + 22 + 1) ? ERANGE : EINVAL);
return NULL;
}
if (!count) count = 5;
output[0] = '$';
output[1] = '2';
output[2] = prefix[2];
output[3] = '$';
output[4] = '0' + count / 10;
output[5] = '0' + count % 10;
output[6] = '$';
BF_encode(&output[7], (const BF_word *)input, 16);
output[7 + 22] = '\0';
return output;
}
char *crypt_rn(const char *key,
int inLen,
const char *setting,
void *data,
int size)
{
return _crypt_blowfish_rn(key, inLen, setting, (char *)data, size);
}

View File

@ -0,0 +1,32 @@
/*
* Written by Solar Designer <solar at openwall.com> in 2000-2011.
* No copyright is claimed, and the software is hereby placed in the public
* domain. In case this attempt to disclaim copyright and place the software
* in the public domain is deemed null and void, then the software is
* Copyright (c) 2000-2011 Solar Designer and it is hereby released to the
* general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*
* See crypt_blowfish.c for more information.
*/
#ifndef _CRYPT_BLOWFISH_H
#define _CRYPT_BLOWFISH_H
char *crypt_rn(const char *key,
int inLen,
const char *setting,
void *data,
int size);
char *_crypt_gensalt_blowfish_rn(const char *prefix,
unsigned long count,
const char *input,
int size,
char *output,
int output_size);
#endif

View File

@ -336,10 +336,7 @@ namespace Aurora::IO::FS
bool NTWatchObject::Init(const AuString &usrStr)
{
AuCtorCode_t code;
this->strBaseDir = AuTryConstruct<AuString>(code, usrStr);
if (!code)
if (!AuTryConstruct<AuString>(this->strBaseDir, usrStr))
{
return false;
}
@ -449,7 +446,6 @@ namespace Aurora::IO::FS
bool NTWatcher::AddWatch(const WatchRequest &request)
{
AuCtorCode_t code;
AuSPtr<NTWatchObject> watcher;
NTCachedPath cached;
@ -464,14 +460,12 @@ namespace Aurora::IO::FS
}
// Create the NT path in the midst of path normalization
cached.strNormalizedPath = AuTryConstruct<AuString>(code, translated);
if (!code)
if (!AuTryConstruct<AuString>(cached.strNormalizedPath, translated))
{
return false;
}
cached.strTheCakeIsALie = AuTryConstruct<AuString>(code, file.path);
if (!code)
if (!AuTryConstruct<AuString>(cached.strTheCakeIsALie, file.path))
{
return false;
}

View File

@ -5,389 +5,14 @@
Date: 2021-6-11
Author: Reece
***/
#define I_REALLY_NEED_WIDECHAR_PUBAPI
#include <Source/RuntimeInternal.hpp>
#include "Locale.hpp"
#if !defined(AU_NO_CPPLOCALE)
#include <locale>
#include <codecvt>
#endif
#include <wchar.h>
#include <tuple>
#include "LocaleGetLocale.hpp"
namespace Aurora::Locale
{
static AuString gCountryCode;
static AuString gLanguageCode;
static AuString gCodeset;
static ECodePage gInternalCodePage = ECodePage::eEnumInvalid;
// Note: [0] out of touch boomers deprecated std::wstring_convert before going for a nappy. we do not have a replacement yet
// [1] the native win32 implementation appears to be more optimized than MSVC/stl
#if !defined(AU_NO_CPPLOCALE) && !(defined(AURORA_COMPILER_MSVC) && defined(AU_LANG_CPP_20))
static std::wstring_convert<std::codecvt_utf8<wchar_t>> gUtf8Conv;
#endif
AUKN_SYM AuString ConvertFromWChar(const wchar_t *in)
{
try
{
return ConvertFromWChar(in, wcslen(in));
}
catch (...)
{
SysPushErrorMem("ConvertFromWChar failed");
return {};
}
}
AUKN_SYM AuString ConvertFromWChar(const wchar_t *in, AuMach length)
{
try
{
#if defined(AU_HAS_MSFT_NATIONALLANGSUPPORT)
AuString ret;
auto chars = WideCharToMultiByte(CP_UTF8, 0, in, length, NULL, 0, NULL, NULL);
if (!chars)
{
return {};
}
ret.resize(chars);
WideCharToMultiByte(CP_UTF8, 0, in, length, ret.data(), ret.size(), NULL, NULL);
return ret;
#elif !defined(AU_NO_CPPLOCALE)
return gUtf8Conv.to_bytes(std::wstring(in, wcsnlen(in, length)));
#else
SysPushErrorUnimplemented("ConvertFromWChar");
return {};
#endif
}
catch (...)
{
SysPushErrorMem("ConvertFromWChar failed");
Debug::CheckErrors();
}
return {};
}
AUKN_SYM std::wstring ConvertFromUTF8(const AuString &in)
{
try
{
#if defined(AU_HAS_MSFT_NATIONALLANGSUPPORT)
std::wstring ret;
auto chars = MultiByteToWideChar(CP_UTF8, 0, in.c_str(), in.length(), NULL, 0);
if (!chars)
{
return {};
}
ret.resize(chars);
MultiByteToWideChar(CP_UTF8, 0, in.c_str(), in.length(), ret.data(), ret.size());
return ret;
#elif !defined(AU_NO_CPPLOCALE)
return gUtf8Conv.from_bytes(in);
#else
SysPushErrorUnimplemented("ConvertFromUTF8");
return {};
#endif
}
catch (...)
{
SysPushErrorMem("ConvertFromUTF8 failed");
Debug::CheckErrors();
}
return {};
}
ECodePage GetInternalCodePage()
{
return gInternalCodePage;
}
AuString const &GetInternalCodePageString()
{
return gCodeset;
}
#if defined(AU_HAS_MSFT_NATIONALLANGSUPPORT)
static void SetCodesetCommonGuessWin32()
{
int acp = GetACP();
if (acp == CP_CHINESE)
{
gCodeset = "GB18030";
gInternalCodePage = ECodePage::e18030;
}
else if (acp == CP_UTF8)
{
gCodeset = "UTF-8";
gInternalCodePage = ECodePage::eUTF8;
}
else if (acp == CP_UTF_16)
{
gCodeset = "UTF-16";
gInternalCodePage = ECodePage::eUTF16;
}
else if (acp == CP_UTF_16 + 1)
{
gCodeset = "UTF-16";
gInternalCodePage = ECodePage::eUTF16BE;
}
else if (acp == CP_LATIN_1)
{
gCodeset = "Latin-1";
gInternalCodePage = ECodePage::eLatin1;
}
else if (acp == CP_2312_LIMITED_GBK)
{
gCodeset = "GBK";
gInternalCodePage = ECodePage::eGBK;
}
else if (acp == 437)
{
gCodeset = "IBM437";
gInternalCodePage = ECodePage::eSysUnk;
}
else if (acp == CP_SHIFTJIS)
{
gCodeset = "SJIS";
gInternalCodePage = ECodePage::eSJIS;
}
else
{
gCodeset = "MS-" + AuToString(acp);
gInternalCodePage = ECodePage::eSysUnk;
}
}
static void SetLanguageWin32()
{
int ret;
wchar_t name[LOCALE_NAME_MAX_LENGTH] = { 0 };
ret = LCIDToLocaleName(LOCALE_USER_DEFAULT, name, LOCALE_NAME_MAX_LENGTH, LOCALE_ALLOW_NEUTRAL_NAMES);
SysAssert(ret, "Couldn't acquire win32 locale information");
wchar_t language[LOCALE_NAME_MAX_LENGTH] = { 0 };
ret = GetLocaleInfoEx(name, LOCALE_SISO639LANGNAME, language, LOCALE_NAME_MAX_LENGTH);
SysAssert(ret, "Couldn't acquire win32 provided ISO 639 map of {}", ConvertFromWChar(name));
wchar_t country[LOCALE_NAME_MAX_LENGTH] = { 0 };
ret = GetLocaleInfoEx(name, LOCALE_SISO3166CTRYNAME, country, LOCALE_NAME_MAX_LENGTH);
SysAssert(ret, "Couldn't acquire win32 provided ISO 3166 map of {}", ConvertFromWChar(name));
gCountryCode = ConvertFromWChar(country);
gLanguageCode = ConvertFromWChar(language);
SetCodesetCommonGuessWin32();
}
#elif defined(AURORA_IS_POSIX_DERIVED)
static AuHashMap<unsigned char, AuString> ParseLocaleString(const AuString &locale)
{
static auto isCharacterSplitter = [&](unsigned char ch) -> bool
{
static AuList<unsigned char> characterSplitters = { '.', '_', '@' };
for (auto const splitter : characterSplitters)
{
if (splitter == ch)
{
return true;
}
}
return false;
};
AuHashMap<unsigned char, AuString> parseTable;
AuMach startingIndex = 0;
unsigned char startingCharacter = '!';
for (AuMach i = 0; i < locale.size(); i++)
{
unsigned char curCh = locale[i];
if (!(isCharacterSplitter(curCh)))
{
continue;
}
parseTable.insert(AuMakePair(startingCharacter, locale.substr(startingIndex, i - startingIndex)));
startingIndex = i + 1;
startingCharacter = curCh;
}
parseTable.insert(AuMakePair(startingCharacter, locale.substr(startingIndex, locale.size() - startingIndex)));
return parseTable;
}
static void SetLanguageUnix()
{
#if 0
// this doesn't seem to work with libc++ lol?
auto locale = -std::--locale("").name();
#else
setlocale(LC_ALL, "");
AuString locale = setlocale(LC_ALL, NULL);
#endif
if (locale == "C")
{
AuLogWarn("Improperly configured UNIX environment.");
AuLogWarn("This localization detection code was written in 2020, please follow the `language[_territory][.codeset][@modifier]` convention for user/sys locales.");
AuLogWarn("'C' is not a language, country, or anything with which we can discern anything meaningful from. Fix your scuffed unix operating system and try again later...");
SysPanic("You fools");
}
auto parseTable = ParseLocaleString(locale);
AuString *lc;
if ((AuTryFind(parseTable, '!', lc)) && (lc->size()))
{
gLanguageCode = *lc;
}
else
{
AuLogWarn("Improperly configured UNIX environment.");
AuLogWarn("Couldn't discern language from localization string: {}", locale);
SysPanic("You fools");
}
AuString *cc;
if ((AuTryFind(parseTable, '_', cc)) && (cc->size()))
{
gCountryCode = *cc;
}
else
{
gCountryCode = "GB";
}
AuString *cs;
if ((AuTryFind(parseTable, '.', cs)) && (cs->size()))
{
gCodeset = *cs;
}
else
{
gCodeset = "UTF-8"; //also technically not true, but most UNIX/Linux applications expect UTF8 byte stirngs or UTF-32 wchar_t strings. this assumption shouldn't break anything
}
}
#define AURORA_HAS_UNIXLOCALE
#endif
#if defined(AURORA_PLATFORM_WIN32) || defined(AURORA_PLATFORM_LINUX) || defined(AURORA_PLATFORM_BSD)
static void SetLanguageEnvBlock()
{
const char *language;
if ((language = getenv("AURORA_ENV_LANGUAGE")))
{
gLanguageCode = language;
}
const char *countryCode;
if ((countryCode = getenv("AURORA_ENV_COUNTRY")))
{
gCountryCode = countryCode;
}
// You may not overload codeset on win32 targets
const char *codeSet;
if ((codeSet = getenv("AURORA_ENV_CODESET")))
{
gCodeset = codeSet;
}
}
#define AURORA_HAS_ENVBLOCK
#endif
static void GuessSystemECodePage()
{
if (gInternalCodePage != ECodePage::eEnumInvalid)
{
return;
}
if (gCodeset == "UTF-8")
{
gInternalCodePage = ECodePage::eUTF8;
}
else if (gCodeset == "UTF-16")
{
// TODO: is big endian
gInternalCodePage = ECodePage::eUTF16;
}
else if (gCodeset == "UTF-32")
{
// TODO: is big endian
gInternalCodePage = ECodePage::eUTF32;
}
else if (gCodeset == "SJIS")
{
gInternalCodePage = ECodePage::eSJIS;
}
// a history of chinese locales
else if (gCodeset == "GB18030") // is the new legally defined standard
{
gInternalCodePage = ECodePage::e18030;
}
else if (gCodeset == "GBK") // GB18030 is derived from GBK, GBK is drived from GB2312
{
gInternalCodePage = ECodePage::eGBK;
}
else if (gCodeset == "GB2312") // GBK is drived from GB2312, GB2312 is derived from telegraph shid
{
gInternalCodePage = ECodePage::e2312;
}
else
{
gInternalCodePage = ECodePage::eSysUnk;
}
}
void Init()
{
#if defined(AU_HAS_MSFT_NATIONALLANGSUPPORT)
SetLanguageWin32();
#elif defined(AURORA_HAS_UNIXLOCALE)
SetLanguageUnix();
#endif
#if defined(AURORA_HAS_ENVBLOCK)
SetLanguageEnvBlock();
#endif
GuessSystemECodePage();
gLanguageCode = AuToLower(gLanguageCode);
gCountryCode = AuToUpper(gCountryCode);
gCodeset = gCodeset;
Encoding::InitIConv();
}
static bool gLockLocale = false;
AUKN_SYM void RuntimeOverloadLocality(const AuPair<AuString, AuString> &locality)
{
SysAssert(!AuExchange(gLockLocale, true), "Locality has been locked");
gLanguageCode = AuToLower(locality.first);
gCountryCode = AuToUpper(locality.second);
}
AUKN_SYM LocalizationInfo GetLocale()
{
gLockLocale = true;
return LocalizationInfo(gLanguageCode, gCountryCode, gCodeset, gInternalCodePage);
InitPlatformLocale();
}
}

View File

@ -0,0 +1,103 @@
/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: LocaleConvertWide.cpp
Date: 2022-9-15
File: Locale.cpp
Date: 2021-6-11
Author: Reece
***/
#define I_REALLY_NEED_WIDECHAR_PUBAPI
#include <Source/RuntimeInternal.hpp>
#include "Locale.hpp"
#if !defined(AU_NO_CPPLOCALE)
#include <locale>
#include <codecvt>
#endif
#include <wchar.h>
namespace Aurora::Locale
{
// Note: [0] out of touch boomers deprecated std::wstring_convert before going for a nappy. we do not have a replacement yet
// [1] the native win32 implementation appears to be more optimized than MSVC/stl
#if !defined(AU_NO_CPPLOCALE) && !(defined(AURORA_COMPILER_MSVC) && defined(AU_LANG_CPP_20))
static std::wstring_convert<std::codecvt_utf8<wchar_t>> gUtf8Conv;
#endif
AUKN_SYM AuString ConvertFromWChar(const wchar_t *in)
{
try
{
return ConvertFromWChar(in, wcslen(in));
}
catch (...)
{
SysPushErrorMem("ConvertFromWChar failed");
return {};
}
}
AUKN_SYM AuString ConvertFromWChar(const wchar_t *in, AuMach length)
{
try
{
#if defined(AU_HAS_MSFT_NATIONALLANGSUPPORT)
AuString ret;
auto chars = WideCharToMultiByte(CP_UTF8, 0, in, length, NULL, 0, NULL, NULL);
if (!chars)
{
return {};
}
ret.resize(chars);
WideCharToMultiByte(CP_UTF8, 0, in, length, ret.data(), ret.size(), NULL, NULL);
return ret;
#elif !defined(AU_NO_CPPLOCALE)
return gUtf8Conv.to_bytes(std::wstring(in, wcsnlen(in, length)));
#else
SysPushErrorUnimplemented("ConvertFromWChar");
return {};
#endif
}
catch (...)
{
SysPushErrorMem("ConvertFromWChar failed");
Debug::CheckErrors();
}
return {};
}
AUKN_SYM std::wstring ConvertFromUTF8(const AuString &in)
{
try
{
#if defined(AU_HAS_MSFT_NATIONALLANGSUPPORT)
std::wstring ret;
auto chars = MultiByteToWideChar(CP_UTF8, 0, in.c_str(), in.length(), NULL, 0);
if (!chars)
{
return {};
}
ret.resize(chars);
MultiByteToWideChar(CP_UTF8, 0, in.c_str(), in.length(), ret.data(), ret.size());
return ret;
#elif !defined(AU_NO_CPPLOCALE)
return gUtf8Conv.from_bytes(in);
#else
SysPushErrorUnimplemented("ConvertFromUTF8");
return {};
#endif
}
catch (...)
{
SysPushErrorMem("ConvertFromUTF8 failed");
Debug::CheckErrors();
}
return {};
}
}

View File

@ -0,0 +1,13 @@
/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: LocaleConvertWide.hpp
Date: 2022-9-15
Author: Reece
***/
#pragma once
namespace Aurora::Locale
{
}

View File

@ -0,0 +1,312 @@
/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: LocaleConvertWide.cpp
Date: 2022-9-15
File: Locale.cpp
Date: 2021-6-11
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include "Locale.hpp"
#if !defined(AU_NO_CPPLOCALE)
#include <locale>
#include <codecvt>
#endif
#include <wchar.h>
#include <tuple>
namespace Aurora::Locale
{
static bool gLockLocale = false;
static AuString gCountryCode;
static AuString gLanguageCode;
static AuString gCodeset;
static ECodePage gInternalCodePage = ECodePage::eEnumInvalid;
ECodePage GetInternalCodePage()
{
return gInternalCodePage;
}
AuString const &GetInternalCodePageString()
{
return gCodeset;
}
#if defined(AU_HAS_MSFT_NATIONALLANGSUPPORT)
static void SetCodesetCommonGuessWin32()
{
int acp = GetACP();
if (acp == CP_CHINESE)
{
gCodeset = "GB18030";
gInternalCodePage = ECodePage::e18030;
}
else if (acp == CP_UTF8)
{
gCodeset = "UTF-8";
gInternalCodePage = ECodePage::eUTF8;
}
else if (acp == CP_UTF_16)
{
gCodeset = "UTF-16";
gInternalCodePage = ECodePage::eUTF16;
}
else if (acp == CP_UTF_16 + 1)
{
gCodeset = "UTF-16";
gInternalCodePage = ECodePage::eUTF16BE;
}
else if (acp == CP_LATIN_1)
{
gCodeset = "Latin-1";
gInternalCodePage = ECodePage::eLatin1;
}
else if (acp == CP_2312_LIMITED_GBK)
{
gCodeset = "GBK";
gInternalCodePage = ECodePage::eGBK;
}
else if (acp == 437)
{
gCodeset = "IBM437";
gInternalCodePage = ECodePage::eSysUnk;
}
else if (acp == CP_SHIFTJIS)
{
gCodeset = "SJIS";
gInternalCodePage = ECodePage::eSJIS;
}
else
{
gCodeset = "MS-" + AuToString(acp);
gInternalCodePage = ECodePage::eSysUnk;
}
}
static void SetLanguageWin32()
{
int ret;
wchar_t name[LOCALE_NAME_MAX_LENGTH] = { 0 };
ret = LCIDToLocaleName(LOCALE_USER_DEFAULT, name, LOCALE_NAME_MAX_LENGTH, LOCALE_ALLOW_NEUTRAL_NAMES);
SysAssert(ret, "Couldn't acquire win32 locale information");
wchar_t language[LOCALE_NAME_MAX_LENGTH] = { 0 };
ret = GetLocaleInfoEx(name, LOCALE_SISO639LANGNAME, language, LOCALE_NAME_MAX_LENGTH);
SysAssert(ret, "Couldn't acquire win32 provided ISO 639 map of {}", ConvertFromWChar(name));
wchar_t country[LOCALE_NAME_MAX_LENGTH] = { 0 };
ret = GetLocaleInfoEx(name, LOCALE_SISO3166CTRYNAME, country, LOCALE_NAME_MAX_LENGTH);
SysAssert(ret, "Couldn't acquire win32 provided ISO 3166 map of {}", ConvertFromWChar(name));
gCountryCode = ConvertFromWChar(country);
gLanguageCode = ConvertFromWChar(language);
SetCodesetCommonGuessWin32();
}
#elif defined(AURORA_IS_POSIX_DERIVED)
static AuHashMap<unsigned char, AuString> ParseLocaleString(const AuString &locale)
{
static auto isCharacterSplitter = [&](unsigned char ch) -> bool
{
static AuList<unsigned char> characterSplitters = { '.', '_', '@' };
for (auto const splitter:characterSplitters)
{
if (splitter == ch)
{
return true;
}
}
return false;
};
AuHashMap<unsigned char, AuString> parseTable;
AuMach startingIndex = 0;
unsigned char startingCharacter = '!';
for (AuMach i = 0; i < locale.size(); i++)
{
unsigned char curCh = locale[i];
if (!(isCharacterSplitter(curCh)))
{
continue;
}
parseTable.insert(AuMakePair(startingCharacter, locale.substr(startingIndex, i - startingIndex)));
startingIndex = i + 1;
startingCharacter = curCh;
}
parseTable.insert(AuMakePair(startingCharacter, locale.substr(startingIndex, locale.size() - startingIndex)));
return parseTable;
}
static void SetLanguageUnix()
{
#if 0
// this doesn't seem to work with libc++ lol?
auto locale = -std::--locale("").name();
#else
setlocale(LC_ALL, "");
AuString locale = setlocale(LC_ALL, NULL);
#endif
if (locale == "C")
{
AuLogWarn("Improperly configured UNIX environment.");
AuLogWarn("This localization detection code was written in 2020, please follow the `language[_territory][.codeset][@modifier]` convention for user/sys locales.");
AuLogWarn("'C' is not a language, country, or anything with which we can discern anything meaningful from. Fix your scuffed unix operating system and try again later...");
SysPanic("You fools");
}
auto parseTable = ParseLocaleString(locale);
AuString *lc;
if ((AuTryFind(parseTable, '!', lc)) && (lc->size()))
{
gLanguageCode = *lc;
}
else
{
AuLogWarn("Improperly configured UNIX environment.");
AuLogWarn("Couldn't discern language from localization string: {}", locale);
SysPanic("You fools");
}
AuString *cc;
if ((AuTryFind(parseTable, '_', cc)) && (cc->size()))
{
gCountryCode = *cc;
}
else
{
gCountryCode = "GB";
}
AuString *cs;
if ((AuTryFind(parseTable, '.', cs)) && (cs->size()))
{
gCodeset = *cs;
}
else
{
gCodeset = "UTF-8"; //also technically not true, but most UNIX/Linux applications expect UTF8 byte stirngs or UTF-32 wchar_t strings. this assumption shouldn't break anything
}
}
#define AURORA_HAS_UNIXLOCALE
#endif
#if defined(AURORA_PLATFORM_WIN32) || defined(AURORA_PLATFORM_LINUX) || defined(AURORA_PLATFORM_BSD)
static void SetLanguageEnvBlock()
{
const char *language;
if ((language = getenv("AURORA_ENV_LANGUAGE")))
{
gLanguageCode = language;
}
const char *countryCode;
if ((countryCode = getenv("AURORA_ENV_COUNTRY")))
{
gCountryCode = countryCode;
}
// You may not overload codeset on win32 targets
const char *codeSet;
if ((codeSet = getenv("AURORA_ENV_CODESET")))
{
gCodeset = codeSet;
}
}
#define AURORA_HAS_ENVBLOCK
#endif
static void GuessSystemECodePage()
{
if (gInternalCodePage != ECodePage::eEnumInvalid)
{
return;
}
if (gCodeset == "UTF-8")
{
gInternalCodePage = ECodePage::eUTF8;
}
else if (gCodeset == "UTF-16")
{
// TODO: is big endian
gInternalCodePage = ECodePage::eUTF16;
}
else if (gCodeset == "UTF-32")
{
// TODO: is big endian
gInternalCodePage = ECodePage::eUTF32;
}
else if (gCodeset == "SJIS")
{
gInternalCodePage = ECodePage::eSJIS;
}
// a history of chinese locales
else if (gCodeset == "GB18030") // is the new legally defined standard
{
gInternalCodePage = ECodePage::e18030;
}
else if (gCodeset == "GBK") // GB18030 is derived from GBK, GBK is drived from GB2312
{
gInternalCodePage = ECodePage::eGBK;
}
else if (gCodeset == "GB2312") // GBK is drived from GB2312, GB2312 is derived from telegraph shid
{
gInternalCodePage = ECodePage::e2312;
}
else
{
gInternalCodePage = ECodePage::eSysUnk;
}
}
void InitPlatformLocale()
{
#if defined(AU_HAS_MSFT_NATIONALLANGSUPPORT)
SetLanguageWin32();
#elif defined(AURORA_HAS_UNIXLOCALE)
SetLanguageUnix();
#endif
#if defined(AURORA_HAS_ENVBLOCK)
SetLanguageEnvBlock();
#endif
GuessSystemECodePage();
gLanguageCode = AuToLower(gLanguageCode);
gCountryCode = AuToUpper(gCountryCode);
gCodeset = gCodeset;
Encoding::InitIConv();
}
AUKN_SYM void RuntimeOverloadLocality(const AuPair<AuString, AuString> &locality)
{
SysAssert(!AuExchange(gLockLocale, true), "Locality has been locked");
gLanguageCode = AuToLower(locality.first);
gCountryCode = AuToUpper(locality.second);
}
AUKN_SYM LocalizationInfo GetLocale()
{
gLockLocale = true;
return LocalizationInfo(gLanguageCode, gCountryCode, gCodeset, gInternalCodePage);
}
}

View File

@ -0,0 +1,13 @@
/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: LocaleGetLocale.hpp
Date: 2022-9-15
Author: Reece
***/
#pragma once
namespace Aurora::Locale
{
void InitPlatformLocale();
}

View File

@ -362,7 +362,6 @@ namespace Aurora::Parse
static bool ConsumeTokenPrimitiveish(ParseState &state, ParsableTag type, ParseValue &out)
{
AuCtorCode_t code;
AuString str;
if (!ConsumeStringifedToken(state, type, str))

View File

@ -99,31 +99,3 @@ namespace Aurora::Processes
OpenUri(AuIOFS::NormalizePathRet(file));
}
}
// TODO: Consider creating blocking apis whose return value is an IProcess (construct from ShellExecuteExW -> in.hProcess, or ("xdg-start", ...))
// For the most part, blocking for a specific application in the context of a protocol or file open request is a dated computing construct.
// Nowdays, opening an editor, mail client, or such like means poking a single executable that'll spawn a fuck ton of background workers, io threads,
// and other resources, to manage multiple instances of whatever the application deals with (think: editor tabs; browser windows; sendto: isnt a modal)
// [*1] :
// We probably ran out of memory.
// AuProcess/Open can safely drop as we expect shells to be kinda fucky and async
//
// Case in point: Minecraft on Linux (would?) blocks when you click a link in chat
//
// Fuck tons of applications support clicking of links, in the case of TS and others, allowing for RCE.
// In the case of MC and others, they don't even know if the operation blocks until the process closes.
// Assuming non-blocking, the API returns false on failure; but if it's blocking, who knows what that
// means... Nonzero exit code? Not enough resources? No error?
//
// Websites, programs, and scripts wouldn't know how to process "missing protocol handler,"
// "not enough resources," "process crashed before pump," "shell busy." For the most part, we don't
// expect expect the developer to be aware of what happens after a request to open a resource is
// requested. It's a lot of engineering effort for what should be fork, exec("start", ...)
//
// Dropping invalid paths, out of memory during UTF8 conversion, and other IO issues is probably fine.
// Use an actual IProcess object, if you care about spawning and monitoring executables.
// TODO: Move the above comments into something less gross