317 lines
8.3 KiB
C++
317 lines
8.3 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 <Source/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 = AuMin(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, 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;
|
|
|
|
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.Write(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 bool 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;
|
|
|
|
try
|
|
{
|
|
|
|
in.reserve(length * 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 < length; )
|
|
{
|
|
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(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();
|
|
}
|
|
catch (...)
|
|
{
|
|
SysPushErrorCatch("EncodeHex failed");
|
|
in.clear();
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
} |