aboutsummaryrefslogtreecommitdiff
path: root/Src/omBrowser/addressEncoder.cpp
diff options
context:
space:
mode:
authorJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
committerJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
commit20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/omBrowser/addressEncoder.cpp
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz
Initial community commit
Diffstat (limited to 'Src/omBrowser/addressEncoder.cpp')
-rw-r--r--Src/omBrowser/addressEncoder.cpp518
1 files changed, 518 insertions, 0 deletions
diff --git a/Src/omBrowser/addressEncoder.cpp b/Src/omBrowser/addressEncoder.cpp
new file mode 100644
index 00000000..199cc701
--- /dev/null
+++ b/Src/omBrowser/addressEncoder.cpp
@@ -0,0 +1,518 @@
+#include "main.h"
+#include "./addressEncoder.h"
+
+
+#include <wininet.h>
+#include <strsafe.h>
+
+
+typedef struct __ENCODEBUFFER
+{
+ LPWSTR buffer;
+ size_t bufferMax;
+ LPWSTR cursor;
+ size_t remaining;
+} ENCODEBUFFER;
+
+HRESULT AddressEncoder_ReAllocBuffer(ENCODEBUFFER *decoder, size_t cchBufferSize)
+{
+ if (NULL == decoder)
+ return E_INVALIDARG;
+
+ if (cchBufferSize == decoder->bufferMax)
+ return S_FALSE;
+
+ if (cchBufferSize < decoder->bufferMax)
+ return E_FAIL;
+
+ LPWSTR test = Plugin_ReAllocString(decoder->buffer, cchBufferSize);
+ if (NULL == test)
+ return E_OUTOFMEMORY;
+
+ decoder->cursor = test + (decoder->cursor - decoder->buffer);
+ decoder->remaining += (cchBufferSize - decoder->bufferMax);
+ decoder->buffer = test;
+ decoder->bufferMax = cchBufferSize;
+
+ return S_OK;
+}
+HRESULT AddressEncoder_AppendAnsiString(ENCODEBUFFER *decoder, LPCSTR pszString, size_t cchString)
+{
+ if (NULL == decoder)
+ return E_INVALIDARG;
+
+ INT cchConverted;
+ while(0 ==(cchConverted = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, pszString, (int)cchString, decoder->cursor, (int)decoder->remaining)))
+ {
+ DWORD errorCode = GetLastError();
+ if (ERROR_INSUFFICIENT_BUFFER == errorCode)
+ {
+ INT cchNeed = MultiByteToWideChar(CP_UTF8, 0, pszString, (int)cchString, NULL, 0) - (INT)decoder->remaining;
+ if (cchNeed < 32) cchNeed = 32;
+ HRESULT hr = AddressEncoder_ReAllocBuffer(decoder, decoder->bufferMax + cchNeed);
+ if (FAILED(hr))
+ return hr;
+ }
+ else
+ {
+ return HRESULT_FROM_WIN32(errorCode);
+ }
+ }
+
+ if (0 != cchConverted)
+ {
+ decoder->cursor += cchConverted;
+ decoder->remaining -= cchConverted;
+ }
+
+ return S_OK;
+}
+
+HRESULT AddressEncoder_AppendString(ENCODEBUFFER *decoder, LPCWSTR pszString, size_t cchString)
+{
+ if (NULL == decoder)
+ return E_INVALIDARG;
+
+ LPWSTR cursor;
+ size_t remaining;
+
+ HRESULT hr;
+ if (cchString >= decoder->remaining)
+ {
+ hr = AddressEncoder_ReAllocBuffer(decoder, decoder->bufferMax + (cchString - decoder->remaining) + 1);
+ if (FAILED(hr)) return hr;
+ }
+
+ hr = StringCchCopyNEx(decoder->cursor, decoder->remaining, pszString, cchString, &cursor, &remaining, 0);
+ if (SUCCEEDED(hr))
+ {
+ decoder->cursor = cursor;
+ decoder->remaining = remaining;
+ }
+ return hr;
+}
+
+HRESULT AddressEncoder_GetEscapeBlock(LPCWSTR pszEscape, LPCWSTR *ppszEnd, size_t *pcchEscapeLen, LPSTR pszBuffer, UINT *pcbBufferMax)
+{
+ if (NULL == pszEscape || (NULL != pszBuffer && NULL == pcbBufferMax))
+ return E_INVALIDARG;
+
+ UINT cbBinary = 0;
+ WORD charInfo;
+ WCHAR szDigit[3] = {0};
+
+ HRESULT hr = S_OK;
+
+ LPCWSTR cursor = pszEscape;
+ while (L'%' == *cursor)
+ {
+ LPCWSTR testChar = CharNext(cursor);
+ if (L'\0' == *testChar ||
+ FALSE == GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, testChar, 1, &charInfo) ||
+ 0 == (C1_XDIGIT & charInfo))
+ {
+ break;
+ }
+ szDigit[0] = *testChar;
+
+ testChar = CharNext(testChar);
+ if (L'\0' == *testChar ||
+ FALSE == GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, testChar, 1, &charInfo) ||
+ 0 == (C1_XDIGIT & charInfo))
+ {
+ break;
+ }
+
+ szDigit[1] = *testChar;
+ CharUpperBuff(szDigit, 2);
+
+ BYTE binaryData = ((szDigit[0] - ((szDigit[0] <= L'9' ? L'0' : L'A' - 10))) << 4) & 0xf0;
+ binaryData += (szDigit[1] - ((szDigit[1] <= L'9' ? L'0' : L'A' - 10))) & 0x0f;
+ if (NULL != pszBuffer)
+ {
+ if (cbBinary < *pcbBufferMax)
+ pszBuffer[cbBinary] = binaryData;
+ else
+ hr = E_OUTOFMEMORY;
+ }
+ cbBinary++;
+
+ cursor = CharNext(testChar);
+ }
+
+ if (cursor == pszEscape)
+ hr = HRESULT_FROM_WIN32(ERROR_INVALID_BLOCK_LENGTH);
+
+ if (NULL != ppszEnd)
+ *ppszEnd = cursor;
+
+ if (NULL != pcchEscapeLen)
+ *pcchEscapeLen = (size_t)(cursor - pszEscape);
+
+ if (NULL != pcbBufferMax)
+ *pcbBufferMax = cbBinary;
+
+ return hr;
+}
+
+HRESULT AddressEncoder_DecodeString(LPCWSTR pszUrl, LPWSTR *ppResult)
+{
+ if (NULL == pszUrl)
+ {
+ *ppResult = NULL;
+ return S_FALSE;
+ }
+
+ UINT cchUrl = 0;
+ UINT escapeSize = 0;
+ UINT escapeBlockSize,escapeBlockMaxSize = 0;
+ LPCWSTR escapeBlockEnd;
+ for (LPCWSTR cursor = pszUrl; L'\0' != *cursor;)
+ {
+ if (L'%' == *cursor && SUCCEEDED(AddressEncoder_GetEscapeBlock(cursor, &escapeBlockEnd, NULL, NULL, &escapeBlockSize)))
+ {
+ escapeSize += escapeBlockSize;
+ if (escapeBlockSize > escapeBlockMaxSize)
+ escapeBlockMaxSize = escapeBlockSize;
+
+ cursor = escapeBlockEnd;
+ }
+ else
+ {
+ cchUrl++;
+ cursor = CharNext(cursor);
+ }
+ }
+
+ if (0 == escapeSize)
+ {
+ *ppResult = Plugin_CopyString(pszUrl);
+ if (NULL == *ppResult) return E_OUTOFMEMORY;
+ return S_FALSE;
+ }
+
+ HRESULT hr = S_OK;
+
+ ENCODEBUFFER decoder;
+ ZeroMemory(&decoder, sizeof(decoder));
+
+ LPSTR escapeBuffer = Plugin_MallocAnsiString(escapeBlockMaxSize);
+ if (NULL == escapeBuffer)
+ {
+ hr = E_OUTOFMEMORY;
+ }
+ else
+ {
+ hr = AddressEncoder_ReAllocBuffer(&decoder, cchUrl + (escapeSize + 1)* sizeof(WCHAR));
+ if (SUCCEEDED(hr))
+ {
+ LPCWSTR cursor = pszUrl;
+ LPCWSTR copyBlock = cursor;
+
+ for (;;)
+ {
+ escapeBlockSize = escapeBlockMaxSize;
+ if (L'%' == *cursor && SUCCEEDED(AddressEncoder_GetEscapeBlock(cursor, &escapeBlockEnd, NULL, escapeBuffer, &escapeBlockSize)))
+ {
+ if (copyBlock != cursor)
+ {
+ hr = AddressEncoder_AppendString(&decoder, copyBlock, cursor - copyBlock);
+ if (FAILED(hr))
+ break;
+ copyBlock = cursor;
+ }
+
+ HRESULT convertResult = AddressEncoder_AppendAnsiString(&decoder, escapeBuffer, escapeBlockSize);
+ if (L'\0' == *cursor)
+ break;
+
+ cursor = escapeBlockEnd;
+ if (SUCCEEDED(convertResult))
+ {
+ copyBlock = cursor;
+ }
+
+
+
+ continue;
+ }
+
+ if (L'\0' == *cursor)
+ {
+ if (copyBlock != cursor)
+ hr = AddressEncoder_AppendString(&decoder, copyBlock, cursor - copyBlock);
+ break;
+ }
+ else
+ cursor = CharNext(cursor);
+ }
+
+ }
+
+ }
+
+ if (NULL != escapeBuffer)
+ Plugin_FreeAnsiString(escapeBuffer);
+
+ if (FAILED(hr))
+ {
+ Plugin_FreeString(decoder.buffer);
+ decoder.buffer = NULL;
+ }
+ else
+ {
+ *decoder.cursor = L'\0';
+ }
+
+ *ppResult = decoder.buffer;
+
+ return hr;
+}
+HRESULT AddressEncoder_GetWideBlock(LPCWSTR pszWide, LPCWSTR *pszEnd, LPWSTR pszBuffer, size_t *pcchBufferMax)
+{
+ LPCWSTR cursor = pszWide;
+ if (NULL == pszWide)
+ return E_INVALIDARG;
+
+ if (NULL != pszBuffer && NULL == pcchBufferMax)
+ return E_INVALIDARG;
+
+ while (L'\0' == *cursor || *cursor > 0xFF)
+ {
+ if (L'\0' == *cursor)
+ break;
+ cursor = CharNext(cursor);
+ }
+
+ if (NULL != pszEnd)
+ *pszEnd = cursor;
+
+ HRESULT hr = S_OK;
+ size_t cchBuffer = 0;
+
+ if (cursor == pszWide)
+ {
+ hr = S_FALSE;
+ }
+ else
+ {
+ size_t bytesCount = WideCharToMultiByte(CP_UTF8, 0, pszWide, (int)(cursor - pszWide), NULL, 0, NULL, NULL);
+ if (0 == bytesCount)
+ {
+ DWORD errorCode = GetLastError();
+ if (ERROR_SUCCESS != errorCode)
+ hr = HRESULT_FROM_WIN32(errorCode);
+ }
+ else
+ {
+ cchBuffer = 3 * bytesCount;
+ if (NULL != pszBuffer)
+ {
+ if (*pcchBufferMax >= cchBuffer)
+ {
+ LPWSTR p = pszBuffer;
+ BYTE *bytes = ((BYTE*)(pszBuffer + *pcchBufferMax)) - bytesCount;
+ WideCharToMultiByte(CP_UTF8, 0, pszWide, (int)(cursor - pszWide), (LPSTR)bytes, (int)bytesCount, NULL, NULL);
+ for (size_t i = 0; i < bytesCount; i++)
+ {
+ BYTE b = bytes[i];
+ *p++ = L'%';
+ BYTE c = (b >> 4) & 0x0F;
+ *p++ = (c < 10) ? (L'0' + c) : (L'A' + (c -10));
+ c = b & 0x0F;
+ *p++ = (c < 10) ? (L'0' + c) : (L'A' + (c -10));
+ }
+
+ }
+ else
+ {
+ hr = E_OUTOFMEMORY;
+ }
+ }
+ }
+ }
+
+ if (NULL != pcchBufferMax)
+ {
+ *pcchBufferMax = cchBuffer;
+ }
+
+
+ return hr;
+}
+HRESULT AddressEncoder_EncodeWideChars(LPCWSTR pszAddress, size_t cchAddress, LPWSTR *ppResult)
+{
+ if (NULL == ppResult)
+ return E_POINTER;
+
+ if (NULL == pszAddress)
+ {
+ *ppResult = NULL;
+ return S_FALSE;
+ }
+
+ LPCWSTR blockEnd;
+ size_t blockSize;
+ size_t cchResultMax = 0;
+ BOOL needEncode = FALSE;
+ for (LPCWSTR cursor = pszAddress; L'\0' != *cursor;)
+ {
+ if (*cursor > 0xFF && SUCCEEDED(AddressEncoder_GetWideBlock(cursor, &blockEnd, NULL, &blockSize)))
+ {
+ cursor = blockEnd;
+ cchResultMax += blockSize;
+ needEncode = TRUE;
+ }
+ else
+ {
+ cursor = CharNext(cursor);
+ cchResultMax++;
+ }
+ }
+
+ if (FALSE == needEncode)
+ {
+ *ppResult = NULL;
+ return S_FALSE;
+ }
+
+ HRESULT hr;
+ cchResultMax++;
+ LPWSTR result = Plugin_MallocString(cchResultMax);
+ if (NULL == result)
+ hr = E_OUTOFMEMORY;
+ else
+ {
+ LPWSTR cursor = result;
+ size_t remaining = cchResultMax;
+ LPCWSTR address = pszAddress;
+ LPCWSTR addressBlock = address;
+
+ for (;;)
+ {
+ if (*address > 0xFF)
+ {
+ if (addressBlock != address)
+ {
+ hr = StringCchCopyNEx(cursor, remaining, addressBlock, (size_t)(address - addressBlock), &cursor, &remaining, 0);
+ if (FAILED(hr)) break;
+ }
+
+ blockSize = remaining;
+ hr = AddressEncoder_GetWideBlock(address, &address, cursor, &blockSize);
+ if (FAILED(hr)) break;
+
+ cursor += blockSize;
+ remaining -= blockSize;
+
+ addressBlock = address;
+ continue;
+ }
+
+ if (L'\0' == *address)
+ {
+ if (addressBlock != address)
+ {
+ hr = StringCchCopyNEx(cursor, remaining, addressBlock, (size_t)(address - addressBlock), &cursor, &remaining, 0);
+ }
+ break;
+ }
+ else
+ address = CharNext(address);
+ }
+
+ *cursor = L'\0';
+ }
+
+
+
+ if (FAILED(hr))
+ {
+ Plugin_FreeString(result);
+ result = NULL;
+ }
+
+ *ppResult = result;
+ return hr;
+}
+
+HRESULT AddressEncoder_EncodeString(LPCWSTR pszAddress, LPWSTR pszBuffer, size_t *pcchBufferMax, UINT flags)
+{
+ if (NULL == pszBuffer || NULL == pcchBufferMax)
+ return E_INVALIDARG;
+
+ if (NULL == pszAddress || L'\0' == *pszAddress)
+ {
+ *pszBuffer = L'\0';
+ *pcchBufferMax = 0;
+ return S_OK;
+ }
+
+ INT cchAddress = lstrlen(pszAddress);
+ LPCWSTR begin, end;
+ begin = pszAddress;
+ end = pszAddress + cchAddress;
+ WORD charType;
+ while (L'\0' != *begin &&
+ FALSE != GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, begin, 1, &charType) && 0 != (C1_SPACE & charType))
+ {
+ begin = CharNext(begin);
+ }
+ while (begin != end &&
+ FALSE != GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, begin, 1, &charType) && 0 != (C1_SPACE & charType))
+ {
+ end = CharPrev(begin, end);
+ }
+
+ if (end <= begin)
+ {
+ *pszBuffer = L'\0';
+ *pcchBufferMax = 0;
+ return S_OK;
+ }
+
+ LPWSTR encoded;
+ HRESULT hr = AddressEncoder_EncodeWideChars(begin, (end - begin), &encoded);
+ if (FAILED(hr)) return hr;
+
+ if (S_OK == hr)
+ {
+ begin = encoded;
+ end = begin + lstrlen(begin);
+ }
+
+ DWORD bufferLen = (DWORD)(*pcchBufferMax);
+ if (FALSE == InternetCanonicalizeUrl(begin, pszBuffer, &bufferLen, flags))
+ {
+ DWORD errorCode = GetLastError();
+ if (ERROR_INSUFFICIENT_BUFFER == errorCode)
+ {
+ *pcchBufferMax = bufferLen;
+ hr = ENC_E_INSUFFICIENT_BUFFER;
+ }
+ else
+ {
+ size_t cchNeeded = (end - begin);
+ if (cchNeeded < *pcchBufferMax)
+ {
+ hr = StringCchCopyN(pszBuffer, *pcchBufferMax, begin, cchNeeded);
+ if (STRSAFE_E_INSUFFICIENT_BUFFER == hr)
+ {
+ hr = ENC_E_INSUFFICIENT_BUFFER;
+ }
+ }
+ else
+ {
+ hr = ENC_E_INSUFFICIENT_BUFFER;
+ }
+ *pcchBufferMax = cchNeeded + 1;
+ }
+ }
+
+ else
+ hr = S_OK;
+
+
+ Plugin_FreeString(encoded);
+ return hr;
+} \ No newline at end of file