Jamie Reece Wilson
83f34b0c47
03:28:55:638 17>2 of 53388 functions (<0.1%) were compiled, the rest were copied from previous compilation. 03:28:55:638 17> 0 functions were new in current compilation 03:28:55:638 17> 65 functions had inline decision re-evaluated but remain unchanged 03:28:56:749 17>Finished generating code the header of const AuString & is the same as std::string_view therefore nothing changes. in fact, we still need to alloc strings a bunch of times for a zero terminated string. worse, <c++20 always allocs each time we want to access a hashmap with o(1) lookup, making small hashmaps kinda pointless when we always have to alloc+copy (thx std) perhaps this will help some language binders
340 lines
9.1 KiB
C++
340 lines
9.1 KiB
C++
/***
|
|
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
|
|
|
File: AuHex.cpp
|
|
Date: 2021-8-28
|
|
Author: Reece
|
|
***/
|
|
#include <Source/RuntimeInternal.hpp>
|
|
#include "AuHex.hpp"
|
|
|
|
namespace Aurora::Parse
|
|
{
|
|
static bool HexToOctet(const char *hex, AuUInt8 &val)
|
|
{
|
|
val = 0;
|
|
|
|
for (auto i = 0u; i < 2; i++)
|
|
{
|
|
AuUInt8 byte = *hex++;
|
|
|
|
if (byte >= '0' && byte <= '9')
|
|
{
|
|
byte = byte - '0';
|
|
}
|
|
else if (byte >= 'A' && byte <= 'F')
|
|
{
|
|
byte = byte - 'A' + 10;
|
|
}
|
|
else if (byte >= 'a' && byte <= 'f')
|
|
{
|
|
byte = byte - 'a' + 10;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
|
|
val = (val << 4) | (byte & 0xF);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
AUKN_SYM bool HexToInt(const AuROString &hex, AuUInt64 &val)
|
|
{
|
|
auto pHex = hex.data();
|
|
auto uLength = hex.length();
|
|
|
|
val = 0;
|
|
uLength = AuMin(AuUInt32(sizeof(AuUInt64) * 2), uLength);
|
|
|
|
if (!pHex && uLength)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (auto i = 0u; i < uLength; i++)
|
|
{
|
|
AuUInt8 byte = *pHex++;
|
|
|
|
if (byte >= '0' && byte <= '9')
|
|
{
|
|
byte = byte - '0';
|
|
}
|
|
else if (byte >= 'A' && byte <= 'F')
|
|
{
|
|
byte = byte - 'A' + 10;
|
|
}
|
|
else if (byte >= 'a' && byte <= 'f')
|
|
{
|
|
byte = byte - 'a' + 10;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
|
|
val = (val << 4) | (byte & 0xF);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
AUKN_SYM bool HexToByte(const char (hex)[2], AuUInt8 &val)
|
|
{
|
|
return HexToOctet(hex, val);
|
|
}
|
|
|
|
static inline char NibbleToChar(AuUInt8 nib)
|
|
{
|
|
if (nib < 10)
|
|
return '0' + nib;
|
|
else
|
|
return 'A' + (nib - 10);
|
|
}
|
|
|
|
AUKN_SYM void ByteToHex(AuUInt8 val, char (& hex)[2])
|
|
{
|
|
AuUInt8 lowNibble = val & 0xF;
|
|
AuUInt8 hiNibble = (val >> 4) & 0xF;
|
|
|
|
hex[0] = NibbleToChar(hiNibble);
|
|
hex[1] = NibbleToChar(lowNibble);
|
|
}
|
|
|
|
AUKN_SYM bool DecodeHex(const AuROString &in, AuByteBuffer &out)
|
|
{
|
|
#define HEX_GRAMMAR_CONSUME_ALL(x) \
|
|
for (; i < in.size(); i++) \
|
|
{ \
|
|
if (in[i] != x) \
|
|
{ \
|
|
break; \
|
|
} \
|
|
}
|
|
|
|
#define HEX_GRAMMAR_CONSUME_ONE(x) \
|
|
if (i < in.size()) \
|
|
{ \
|
|
if (in[i] == x) \
|
|
{ \
|
|
i ++; \
|
|
} \
|
|
}
|
|
|
|
#define HEX_GRAMMAR_CONSUME_EITHER(a, b) \
|
|
if (i < in.size()) \
|
|
{ \
|
|
if ((in[i] == a) || \
|
|
(in[i] == b)) \
|
|
{ \
|
|
i++; \
|
|
} \
|
|
}
|
|
|
|
#define HEX_GRAMMAR_CONSUME_SPACE \
|
|
HEX_GRAMMAR_CONSUME_ALL(' ')
|
|
|
|
#define HEX_GRAMMAR_CONSUME_NEW_LINE \
|
|
HEX_GRAMMAR_CONSUME_ONE('\r') \
|
|
HEX_GRAMMAR_CONSUME_ALL('\n')
|
|
|
|
#define HEX_GRAMMAR_CONSUME_END_OF_LINE \
|
|
HEX_GRAMMAR_CONSUME_SPACE \
|
|
HEX_GRAMMAR_CONSUME_NEW_LINE \
|
|
HEX_GRAMMAR_CONSUME_SPACE
|
|
|
|
AuUInt i = 0u;
|
|
|
|
auto writeView = out.GetOrAllocateLinearWriteable(in.size() / 2);
|
|
if (!writeView)
|
|
{
|
|
SysPushErrorMem();
|
|
return false;
|
|
}
|
|
|
|
// Consume whitespace and/or literal start
|
|
{
|
|
HEX_GRAMMAR_CONSUME_SPACE;
|
|
HEX_GRAMMAR_CONSUME_EITHER('{', '[');
|
|
HEX_GRAMMAR_CONSUME_END_OF_LINE;
|
|
}
|
|
|
|
// Consume array
|
|
for (; i < in.size(); )
|
|
{
|
|
// Consume 0x prefix
|
|
if ((i + 1) < in.size())
|
|
{
|
|
if ((in[i] == '0') &&
|
|
(in[i + 1] == 'x'))
|
|
{
|
|
i += 2;
|
|
}
|
|
}
|
|
|
|
// Consume octal
|
|
if ((i + 1) < in.size())
|
|
{
|
|
AuUInt8 byte;
|
|
|
|
if (!HexToOctet(&in[i], byte))
|
|
{
|
|
out.clear();
|
|
return false;
|
|
}
|
|
|
|
*(out.writePtr++) = byte;
|
|
i += 2;
|
|
}
|
|
|
|
HEX_GRAMMAR_CONSUME_ONE('h'); // some hex dump code and people prefer FFh over 0xFF
|
|
|
|
HEX_GRAMMAR_CONSUME_EITHER(':' /*wireshark and other networking tools*/, ',' /*latin array splitter*/);
|
|
HEX_GRAMMAR_CONSUME_END_OF_LINE; // all whitespace [+newline[+all whitespace]]
|
|
|
|
// Consume end literal hint
|
|
if (i < in.size())
|
|
{
|
|
if ((in[i] == '}' /*c-like*/) ||
|
|
(in[i] == ']' /*more latin array tag*/))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
AUKN_SYM bool EncodeHex(Memory::MemoryViewRead view, EHexDump formatting, AuString &in)
|
|
{
|
|
auto pBuf = view.ptr;
|
|
auto uLength = view.length;
|
|
|
|
bool hexedit = formatting == EHexDump::eHexEditor;
|
|
|
|
bool squareBracket = formatting == EHexDump::eJSLiteral;
|
|
bool curlyBracket = formatting == EHexDump::eCLiteral;
|
|
|
|
bool zeroX = formatting == EHexDump::eCLiteral ||
|
|
formatting == EHexDump::eJSLiteral ||
|
|
formatting == EHexDump::eZeroXSpace;
|
|
|
|
bool space = formatting != EHexDump::eString;
|
|
|
|
if (!pBuf && uLength)
|
|
{
|
|
SysPushErrorArg();
|
|
return false;
|
|
}
|
|
|
|
try
|
|
{
|
|
AuTryReserve(in, uLength * 4);
|
|
|
|
auto &newLine = AuLocale::NewLine();
|
|
|
|
if (hexedit)
|
|
{
|
|
in.insert(in.size(), "00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15");
|
|
in.insert(in.size(), newLine);
|
|
in.insert(in.size(), "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
|
|
in.insert(in.size(), newLine);
|
|
in.insert(in.size(), " ");
|
|
in.insert(in.size(), newLine);
|
|
}
|
|
else if (squareBracket)
|
|
{
|
|
in.insert(in.end(), '[');
|
|
in.insert(in.size(), newLine);
|
|
}
|
|
else if (curlyBracket)
|
|
{
|
|
in.insert(in.end(), '{');
|
|
in.insert(in.size(), newLine);
|
|
}
|
|
|
|
for (auto i = 0u; i < uLength; )
|
|
{
|
|
AuUInt32 x, rowMax;
|
|
|
|
if (i != 0)
|
|
{
|
|
if (hexedit || squareBracket || curlyBracket)
|
|
{
|
|
in.insert(in.size(), newLine);
|
|
}
|
|
}
|
|
|
|
if (squareBracket || curlyBracket)
|
|
{
|
|
in.insert(in.size(), " ");
|
|
}
|
|
|
|
rowMax = AuMin(AuUInt32(i + 16), AuUInt32(uLength));
|
|
|
|
for (x = i;
|
|
x < rowMax;
|
|
x++)
|
|
{
|
|
if (space)
|
|
{
|
|
if (x != i)
|
|
{
|
|
in.insert(in.end(), ' ');
|
|
}
|
|
}
|
|
|
|
if (zeroX)
|
|
{
|
|
in.insert(in.size(), "0x");
|
|
}
|
|
|
|
{
|
|
char hex[2];
|
|
ByteToHex(reinterpret_cast<const AuUInt8 *>(pBuf)[x], hex);
|
|
in.insert(in.size(), hex, 2);
|
|
}
|
|
|
|
if (x != (uLength - 1))
|
|
{
|
|
if (squareBracket || curlyBracket)
|
|
{
|
|
in.insert(in.end(), ',');
|
|
}
|
|
}
|
|
}
|
|
|
|
i = x;
|
|
|
|
if (hexedit)
|
|
{
|
|
// TODO: print space + i * 16 padded + space hex(i * 16 padded)
|
|
}
|
|
}
|
|
|
|
if (squareBracket)
|
|
{
|
|
in.insert(in.size(), newLine);
|
|
in.insert(in.end(), ']');
|
|
}
|
|
else if (curlyBracket)
|
|
{
|
|
in.insert(in.size(), newLine);
|
|
in.insert(in.end(), '}');
|
|
}
|
|
|
|
in.shrink_to_fit();
|
|
}
|
|
catch (...)
|
|
{
|
|
SysPushErrorCatch("EncodeHex failed");
|
|
in.clear();
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
} |