diff --git a/build/wxExtend.vcxproj b/build/wxExtend.vcxproj
index 5e70355..6522d3d 100644
--- a/build/wxExtend.vcxproj
+++ b/build/wxExtend.vcxproj
@@ -22,6 +22,7 @@
+
Create
Create
@@ -35,6 +36,7 @@
+
diff --git a/build/wxExtend.vcxproj.filters b/build/wxExtend.vcxproj.filters
index 6cca51e..97b2904 100644
--- a/build/wxExtend.vcxproj.filters
+++ b/build/wxExtend.vcxproj.filters
@@ -34,6 +34,9 @@
Source Files
+
+ Source Files
+
@@ -54,6 +57,9 @@
Header Files
+
+ Header Files
+
diff --git a/include/wxex/hex.h b/include/wxex/hex.h
new file mode 100644
index 0000000..fe5549f
--- /dev/null
+++ b/include/wxex/hex.h
@@ -0,0 +1,206 @@
+/*
+ Copyright 2015-2016 Amebis
+
+ This file is part of wxExtend.
+
+ wxExtend is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ wxExtend is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with wxExtend. If not, see .
+*/
+
+#pragma once
+
+#include "wx/string.h"
+#include "wx/buffer.h"
+
+
+// ----------------------------------------------------------------------------
+// Encoding Functions
+// ----------------------------------------------------------------------------
+
+///
+/// Return the size needed for the buffer containing the encoded representation
+/// of a buffer of given length
+///
+/// \param[in] len Length of the buffer
+/// \returns Maximum encoded representation size (in characters)
+///
+inline size_t wxHexEncodedSize(size_t len)
+{
+ return 2*len;
+}
+
+
+///
+/// Raw hex encoding function which encodes the contents of a buffer of the
+/// specified length into the buffer of the specified size
+///
+/// \param[out] dst Destination buffer to receive Hex encoded data
+/// \param[in] dstLen Length of \p dst buffer (in characters)
+/// \param[in] src Source buffer to encode
+/// \param[in] srcLen Length of \p src buffer (in bytes)
+///
+/// \returns The length of the encoded data or wxCONV_FAILED if the buffer is not
+/// large enough; to determine the needed size you can either allocate a buffer
+/// of \c{wxHexEncodedSize(srcLen)} size or call the function with NULL buffer in
+/// which case the required size will be returned
+///
+size_t WXEXTEND_API wxHexEncode(char *dst, size_t dstLen, const void *src, size_t srcLen);
+
+
+///
+/// Hex encoding function which encodes the contents of a buffer of the
+/// specified length into the wxString
+///
+/// \param[in] src Source buffer to encode
+/// \param[in] srcLen Length of \p src buffer (in bytes)
+///
+/// \returns The hex encoded string
+///
+inline wxString wxHexEncode(const void *src, size_t srcLen)
+{
+ const size_t dstLen = wxHexEncodedSize(srcLen);
+ wxCharBuffer dst(dstLen);
+ wxHexEncode(dst.data(), dstLen, src, srcLen);
+
+ return dst;
+}
+
+
+///
+/// Hex encoding function which encodes the contents of a buffer into the wxString
+///
+/// \param[in] buf Source buffer to encode
+///
+/// \returns The hex encoded string
+///
+inline wxString wxHexEncode(const wxMemoryBuffer& buf)
+{
+ return wxHexEncode(buf.GetData(), buf.GetDataLen());
+}
+
+
+// ----------------------------------------------------------------------------
+// Decoding Functions
+// ----------------------------------------------------------------------------
+
+///
+/// Elements of this enum specify the possible behaviours of wxHexDecode()
+/// when an invalid character is encountered.
+///
+enum wxHexDecodeMode
+{
+ wxHexDecodeMode_Strict, ///< Normal behaviour: stop at any invalid characters
+ wxHexDecodeMode_SkipWS, ///< Skip whitespace characters
+ wxHexDecodeMode_Relaxed, ///< The most lenient behaviour: simply ignore all invalid characters
+};
+
+
+///
+/// Return the buffer size necessary for decoding a hex string of the given
+/// length
+///
+/// \param[in] len Length of the hex encoded string
+/// \returns Maximum decoded representation size (in bytes)
+///
+inline size_t wxHexDecodedSize(size_t len)
+{
+ return (len + 1)/2;
+}
+
+///
+/// Raw decoding function which decodes the contents of the string of specified
+/// length (or zero terminated by default) into the provided buffer of the given
+/// size
+///
+/// The function normally stops at any character invalid inside a hex-encoded
+/// string (i.e. not numeric nor 'A-Z' nor 'a-z') but can be made to skip the
+/// whitespace or all invalid characters using its \p mode argument
+///
+/// \param[out] dst Destination buffer to receive decoded data
+/// \param[in] dstLen Length of \p dst buffer (in bytes)
+/// \param[in] src Source buffer to decode
+/// \param[in] srcLen Length of \p src buffer (in characters) or wxNO_LEN for zero terminated strings
+/// \param[in] mode Desired behaviour on invalid characters (one of \c wxHexDecodeMode constants)
+/// \param[out] posErr Error offset in source buffer (in characters)
+///
+/// \returns The length of the decoded data or wxCONV_FAILED if an error occurs
+/// such as the buffer is too small or the encoded string is invalid; in the
+/// latter case the \p posErr is filled with the position where the decoding
+/// stopped if it is not NULL
+///
+size_t WXEXTEND_API wxHexDecode(void *dst, size_t dstLen, const char *src, size_t srcLen = wxNO_LEN, wxHexDecodeMode mode = wxHexDecodeMode_Strict, size_t *posErr = NULL);
+
+
+///
+/// Decoding function which decodes the contents of the string into the provided buffer of the given size
+///
+/// The function normally stops at any character invalid inside a hex-encoded
+/// string (i.e. not numeric nor 'A-Z' nor 'a-z') but can be made to skip the
+/// whitespace or all invalid characters using its \p mode argument
+///
+/// \param[out] dst Destination buffer to receive decoded data
+/// \param[in] dstLen Length of \p dst buffer (in bytes)
+/// \param[in] src Source string to decode
+/// \param[in] mode Desired behaviour on invalid characters (one of \c wxHexDecodeMode constants)
+/// \param[out] posErr Error offset in source buffer (in characters)
+///
+/// \returns The length of the decoded data or wxCONV_FAILED if an error occurs
+/// such as the buffer is too small or the encoded string is invalid; in the
+/// latter case the \p posErr is filled with the position where the decoding
+/// stopped if it is not NULL
+///
+inline size_t wxHexDecode(void *dst, size_t dstLen, const wxString& src, wxHexDecodeMode mode = wxHexDecodeMode_Strict, size_t *posErr = NULL)
+{
+ // don't use str.length() here as the ASCII buffer is shorter than it is for
+ // strings with embedded NULs
+ return wxHexDecode(dst, dstLen, src.ToAscii(), wxNO_LEN, mode, posErr);
+}
+
+
+///
+/// Decoding function which decodes the contents of the string of specified
+/// length (or zero terminated by default) into the buffer
+///
+/// The function normally stops at any character invalid inside a hex-encoded
+/// string (i.e. not numeric nor 'A-Z' nor 'a-z') but can be made to skip the
+/// whitespace or all invalid characters using its \p mode argument
+///
+/// \param[in] src Source buffer to decode
+/// \param[in] srcLen Length of \p src buffer (in characters) or wxNO_LEN for zero terminated strings
+/// \param[in] mode Desired behaviour on invalid characters (one of \c wxHexDecodeMode constants)
+/// \param[out] posErr Error offset in source buffer (in characters)
+///
+/// \returns Destination buffer with decoded data or an empty buffer if an error occured during decoding
+///
+wxMemoryBuffer WXEXTEND_API wxHexDecode(const char *src, size_t srcLen = wxNO_LEN, wxHexDecodeMode mode = wxHexDecodeMode_Strict, size_t *posErr = NULL);
+
+
+///
+/// Decoding function which decodes the contents of the string into the buffer
+///
+/// The function normally stops at any character invalid inside a hex-encoded
+/// string (i.e. not numeric nor 'A-Z' nor 'a-z') but can be made to skip the
+/// whitespace or all invalid characters using its \p mode argument
+///
+/// \param[in] src Source string to decode
+/// \param[in] mode Desired behaviour on invalid characters (one of \c wxHexDecodeMode constants)
+/// \param[out] posErr Error offset in source buffer (in characters)
+///
+/// \returns Destination buffer with decoded data or an empty buffer if an error occured during decoding
+///
+inline wxMemoryBuffer wxHexDecode(const wxString& src, wxHexDecodeMode mode = wxHexDecodeMode_Strict, size_t *posErr = NULL)
+{
+ // don't use str.length() here as the ASCII buffer is shorter than it for
+ // strings with embedded NULs
+ return wxHexDecode(src.ToAscii(), wxNO_LEN, mode, posErr);
+}
diff --git a/src/hex.cpp b/src/hex.cpp
new file mode 100644
index 0000000..837f321
--- /dev/null
+++ b/src/hex.cpp
@@ -0,0 +1,120 @@
+/*
+ Copyright 2015-2016 Amebis
+
+ This file is part of wxExtend.
+
+ wxExtend is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ wxExtend is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with wxExtend. If not, see .
+*/
+
+#include "stdafx.h"
+
+
+size_t WXEXTEND_API wxHexEncode(char *dst, size_t dstLen, const void *src_, size_t srcLen)
+{
+ wxCHECK_MSG( src_, wxCONV_FAILED, wxT("NULL input buffer") );
+
+ const unsigned char *src = static_cast(src_);
+
+ static const char bhex[] = "0123456789ABCDEF";
+
+ size_t encLen = 0;
+
+ for ( ; srcLen; srcLen--, src++) {
+ encLen += 2;
+ if ( dst )
+ {
+ if ( encLen > dstLen )
+ return wxCONV_FAILED;
+
+ *dst++ = bhex[src[0] >> 4];
+ *dst++ = bhex[src[0] & 0x0f];
+ }
+ }
+
+ return encLen;
+}
+
+
+size_t WXEXTEND_API wxHexDecode(void *dst_, size_t dstLen, const char *src, size_t srcLen, wxHexDecodeMode mode, size_t *posErr)
+{
+ wxCHECK_MSG( src, wxCONV_FAILED, wxT("NULL input buffer") );
+
+ unsigned char *dst = static_cast(dst_);
+
+ size_t decLen = 0;
+
+ if ( srcLen == wxNO_LEN )
+ srcLen = strlen(src);
+
+ // we decode input by groups of 2 characters but things are complicated by
+ // the fact that there can be whitespace and other junk in it too so keep
+ // record of where exactly we're inside the current pair in this var
+ int n = 0;
+ unsigned char in = 0; // current pair
+ const char *p;
+ for ( p = src; srcLen; p++, srcLen-- )
+ {
+ const unsigned char c = static_cast(*p);
+ if ( '0' <= c && c <= '9' ) in = (in << 4) | (c - '0') , n++;
+ else if ( 'A' <= c && c <= 'F' ) in = (in << 4) | (c - 'A' + 10), n++;
+ else if ( 'a' <= c && c <= 'f' ) in = (in << 4) | (c - 'a' + 10), n++;
+ else {
+ if ( mode == wxHexDecodeMode_Relaxed ||
+ mode == wxHexDecodeMode_SkipWS && isspace(c) )
+ continue;
+
+ if ( posErr )
+ *posErr = p - src;
+
+ return wxCONV_FAILED;
+ }
+
+ if ( n == 2 )
+ {
+ // got entire block, save
+ decLen++;
+ if ( dst )
+ {
+ if ( decLen > dstLen )
+ return wxCONV_FAILED;
+
+ *dst++ = in;
+ }
+
+ in = 0;
+ n = 0;
+ }
+ }
+
+ return decLen;
+}
+
+
+wxMemoryBuffer WXEXTEND_API wxHexDecode(const char *src, size_t srcLen, wxHexDecodeMode mode, size_t *posErr)
+{
+ wxMemoryBuffer buf;
+ wxCHECK_MSG( src, buf, wxT("NULL input buffer") );
+
+ if ( srcLen == wxNO_LEN )
+ srcLen = strlen(src);
+
+ size_t len = wxHexDecodedSize(srcLen);
+ len = wxHexDecode(buf.GetWriteBuf(len), len, src, srcLen, mode, posErr);
+ if ( len == wxCONV_FAILED )
+ len = 0;
+
+ buf.SetDataLen(len);
+
+ return buf;
+}
diff --git a/src/stdafx.h b/src/stdafx.h
index 97c9249..986572d 100644
--- a/src/stdafx.h
+++ b/src/stdafx.h
@@ -26,6 +26,7 @@
#include "../include/wxex/appbar.h"
#include "../include/wxex/comutils.h"
#include "../include/wxex/crypto.h"
+#include "../include/wxex/hex.h"
#include "../include/wxex/xml.h"
#include "../include/wxex/common.h"