#include "main.h" #include "./addressEncoder.h" #include #include 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; }