305 lines
8.0 KiB
C++
305 lines
8.0 KiB
C++
|
/***
|
||
|
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||
|
|
||
|
File: Hex.cpp
|
||
|
Date: 2021-8-28
|
||
|
Author: Reece
|
||
|
***/
|
||
|
#include <RuntimeInternal.hpp>
|
||
|
#include "Hex.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 char *hex, AuUInt32 length, AuUInt64 &val)
|
||
|
{
|
||
|
val = 0;
|
||
|
length = std::min(AuUInt32(sizeof(AuUInt64) * 2), length);
|
||
|
|
||
|
for (auto i = 0u; i < length; 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 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 AuString &in, AuList<AuUInt8> &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;
|
||
|
|
||
|
out.reserve(in.size() / 2);
|
||
|
|
||
|
// 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 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.push_back(byte);
|
||
|
i += 2;
|
||
|
}
|
||
|
|
||
|
HEX_GRAMMAR_CONSUME_ONE(',');
|
||
|
HEX_GRAMMAR_CONSUME_END_OF_LINE;
|
||
|
|
||
|
// Consume end literal hint
|
||
|
if (i < in.size())
|
||
|
{
|
||
|
if ((in[i] == '}') ||
|
||
|
(in[i] == ']'))
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
AUKN_SYM void EncodeHex(const void *pBuf, AuUInt32 length, EHexDump formatting, AuString &in)
|
||
|
{
|
||
|
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;
|
||
|
|
||
|
in.reserve(length * 4);
|
||
|
|
||
|
const char *newLine = Aurora::Build::kCurrentVendor == Aurora::Build::EVendor::eGenericMicrosoft ? "\r\n" : "\n";
|
||
|
|
||
|
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 (int i = 0; i < length; )
|
||
|
{
|
||
|
AuUInt32 x, rowMax;
|
||
|
|
||
|
if (i != 0)
|
||
|
{
|
||
|
if (hexedit || squareBracket || curlyBracket)
|
||
|
{
|
||
|
in.insert(in.size(), newLine);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (squareBracket || curlyBracket)
|
||
|
{
|
||
|
in.insert(in.size(), " ");
|
||
|
}
|
||
|
|
||
|
rowMax = std::min(AuUInt32(i + 16), AuUInt32(length));
|
||
|
|
||
|
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 != (length - 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();
|
||
|
}
|
||
|
}
|