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"