import "std_Buffer.jnc"

// port of axl_enc_HexEncoding.cpp

//! \addtogroup common-enc
//! @{

//..............................................................................

bool isHexStringSep(char c) {
	switch (c) {
	case ' ': case '\t': case '\r': case '\n':
	case '.': case ',': case ';': case ':':
		return true;

	default:
		return false;
	}
}

size_t decodeHexString(
	std.Buffer* buffer,
	string_t source
) {
	enum State {
		Normal = 0,
		Hex
	};

	State state = State.Normal;

	buffer.clear();
	buffer.setSize(source.m_length / 2 + 1); // enough to hold everything

	char hexCodeString[4] = { 0 };
	char const* hexCodeEnd;
	size_t hexCodeLen;

	uchar_t x;

	char const* p = source.m_p;
	char const* end = p + source.m_length;

	size_t size = 0;
	for (; p < end; p++) {
		bool isSep = isHexStringSep(*p);

		switch (state) {
		case State.Normal:
			if (isSep)
				break;

			hexCodeString[0] = *p;
			hexCodeLen = 1;
			state = State.Hex;
			break;

		case State.Hex:
			if (!isSep) {
				hexCodeString[hexCodeLen++] = *p;
				if (hexCodeLen < 2)
					break;
			}

			hexCodeString[hexCodeLen] = 0;
			x = (uchar_t)strtoul(hexCodeString, &hexCodeEnd, 16);
			if (hexCodeEnd == &hexCodeString[hexCodeLen])
				buffer[size++] = x;
			else
				p = end; // not a hex string anymore, break the loop

			state = State.Normal;
			break;
		}
	}

	if (state == State.Hex) {
		hexCodeString[hexCodeLen] = 0;
		x = (uchar_t)strtol(hexCodeString, &hexCodeEnd, 16);

		if (hexCodeEnd == &hexCodeString[hexCodeLen])
			buffer[size++] = x;
	}

	buffer.setSize(size); // adjust size
	return size;
}

string_t encodeHexString(
	void const* p,
	size_t size,
	char sep = 0 // 0 means no separator
) {
	static char charTable[] = "0123456789ABCDEF";

	if (!size)
		return null;

	size_t length = size * 2;
	if (sep)
		length += size - 1;

	std.Buffer buffer;
	buffer.setSize(length + 1); // plus null-terminator (not essential)

	char* dst = buffer.m_p;
	uint8_t const* src = p;
	uint8_t const* end = p + size;

	if (!sep)
		for (; src < end; src++) {
			uint8_t x = *src;
			*dst++ = charTable[(x >> 4) & 0x0f];
			*dst++ = charTable[x & 0x0f];
		}
	else {
		memset(dst, sep, length);

		for (; src < end; src++) {
			uint8_t x = *src;
			*dst++ = charTable[(x >> 4) & 0x0f];
			*dst++ = charTable[x & 0x0f];
			dst++; // sep
		}
	}

	return string_t(buffer.m_p, length);
}

//..............................................................................

//! @}
