diff options
author | Tomáš Rylek <trylek@microsoft.com> | 2020-12-08 05:19:44 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-12-08 05:19:44 +0300 |
commit | 69e114c1abf91241a0eeecf1ecceab4711b8aa62 (patch) | |
tree | b81a0b35748f5e598412bcc504335cdbd322cd43 /src/coreclr/palrt | |
parent | 0ec07945a9759a72a689edbb01e69b232e26e05a (diff) |
December infra rollout - remove duplicated 'src' from coreclr subrepo (src/coreclr/src becomes src/coreclr) (#44973)
* Move src/coreclr/src/Directory.Build.targets to src/coreclr
Merge src/coreclr/src/CMakeLists.txt into src/coreclr/CMakeLists.txt
* Mechanical move of src/coreclr/src to src/coreclr
* Scripts adjustments to reflect the changed paths
Diffstat (limited to 'src/coreclr/palrt')
-rw-r--r-- | src/coreclr/palrt/CMakeLists.txt | 20 | ||||
-rw-r--r-- | src/coreclr/palrt/bstr.cpp | 263 | ||||
-rw-r--r-- | src/coreclr/palrt/coguid.cpp | 192 | ||||
-rw-r--r-- | src/coreclr/palrt/comem.cpp | 21 | ||||
-rw-r--r-- | src/coreclr/palrt/common.h | 17 | ||||
-rw-r--r-- | src/coreclr/palrt/guid.cpp | 47 | ||||
-rw-r--r-- | src/coreclr/palrt/memorystream.cpp | 316 | ||||
-rw-r--r-- | src/coreclr/palrt/path.cpp | 646 | ||||
-rw-r--r-- | src/coreclr/palrt/shlwapip.h | 37 | ||||
-rw-r--r-- | src/coreclr/palrt/variant.cpp | 32 |
10 files changed, 1591 insertions, 0 deletions
diff --git a/src/coreclr/palrt/CMakeLists.txt b/src/coreclr/palrt/CMakeLists.txt new file mode 100644 index 00000000000..a4c6fdd5ae8 --- /dev/null +++ b/src/coreclr/palrt/CMakeLists.txt @@ -0,0 +1,20 @@ + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(PALRT_SOURCES + bstr.cpp + coguid.cpp + comem.cpp + guid.cpp + memorystream.cpp + path.cpp + variant.cpp +) + +add_library_clr(palrt + STATIC + ${PALRT_SOURCES} +) + +# Install the static PAL library for VS +_install (TARGETS palrt DESTINATION lib) diff --git a/src/coreclr/palrt/bstr.cpp b/src/coreclr/palrt/bstr.cpp new file mode 100644 index 00000000000..2f5ccd9cd48 --- /dev/null +++ b/src/coreclr/palrt/bstr.cpp @@ -0,0 +1,263 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// + +// +// =========================================================================== +// File: bstr.cpp +// +// =========================================================================== + + +/*++ + +Abstract: + + PALRT BSTR support + +Revision History: + +--*/ + +#include "common.h" +#include "intsafe.h" + +#define CCH_BSTRMAX 0x7FFFFFFF // 4 + (0x7ffffffb + 1 ) * 2 ==> 0xFFFFFFFC +#define CB_BSTRMAX 0xFFFFFFFa // 4 + (0xfffffff6 + 2) ==> 0xFFFFFFFC + +#define WIN32_ALLOC_ALIGN (16 - 1) + +inline HRESULT CbSysStringSize(ULONG cchSize, BOOL isByteLen, ULONG *result) +{ + if (result == NULL) + return E_INVALIDARG; + + // +2 for the null terminator + // + DWORD_PTR to store the byte length of the string + int constant = sizeof(WCHAR) + sizeof(DWORD_PTR) + WIN32_ALLOC_ALIGN; + + if (isByteLen) + { + if (SUCCEEDED(ULongAdd(constant, cchSize, result))) + { + *result = *result & ~WIN32_ALLOC_ALIGN; + return NOERROR; + } + } + else + { + ULONG temp = 0; // should not use in-place addition in ULongAdd + if (SUCCEEDED(ULongMult(cchSize, sizeof(WCHAR), &temp)) & + SUCCEEDED(ULongAdd(temp, constant, result))) + { + *result = *result & ~WIN32_ALLOC_ALIGN; + return NOERROR; + } + } + return INTSAFE_E_ARITHMETIC_OVERFLOW; +} + +/*** +*BSTR SysAllocStringLen(char*, unsigned int) +*Purpose: +* Allocation a bstr of the given length and initialize with +* the pasted in string +* +*Entry: +* [optional] +* +*Exit: +* return value = BSTR, NULL if the allocation failed. +* +***********************************************************************/ +STDAPI_(BSTR) SysAllocStringLen(const OLECHAR *psz, UINT len) +{ + + BSTR bstr; + DWORD cbTotal = 0; + + if (FAILED(CbSysStringSize(len, FALSE, &cbTotal))) + return NULL; + + bstr = (OLECHAR *)PAL_malloc(cbTotal); + + if(bstr != NULL){ + +#if defined(HOST_64BIT) + // NOTE: There are some apps which peek back 4 bytes to look at the size of the BSTR. So, in case of 64-bit code, + // we need to ensure that the BSTR length can be found by looking one DWORD before the BSTR pointer. + *(DWORD_PTR *)bstr = (DWORD_PTR) 0; + bstr = (BSTR) ((char *) bstr + sizeof (DWORD)); +#endif + *(DWORD FAR*)bstr = (DWORD)len * sizeof(OLECHAR); + + bstr = (BSTR) ((char*) bstr + sizeof(DWORD)); + + if(psz != NULL){ + memcpy(bstr, psz, len * sizeof(OLECHAR)); + } + + bstr[len] = '\0'; // always 0 terminate + } + + return bstr; +} + +/*** +*BSTR SysAllocString(char*) +*Purpose: +* Allocation a bstr using the passed in string +* +*Entry: +* String to create a bstr for +* +*Exit: +* return value = BSTR, NULL if allocation failed +* +***********************************************************************/ +STDAPI_(BSTR) SysAllocString(const OLECHAR* psz) +{ + if(psz == NULL) + return NULL; + + return SysAllocStringLen(psz, (DWORD)wcslen(psz)); +} + +STDAPI_(BSTR) +SysAllocStringByteLen(const char FAR* psz, unsigned int len) +{ + BSTR bstr; + DWORD cbTotal = 0; + + if (FAILED(CbSysStringSize(len, TRUE, &cbTotal))) + return FALSE; + + bstr = (OLECHAR *)PAL_malloc(cbTotal); + + if (bstr != NULL) { +#if defined(HOST_64BIT) + *(DWORD FAR*)((char *)bstr + sizeof (DWORD)) = (DWORD)len; +#else + *(DWORD FAR*)bstr = (DWORD)len; +#endif + + bstr = (WCHAR*) ((char*) bstr + sizeof(DWORD_PTR)); + + if (psz != NULL) { + memcpy(bstr, psz, len); + } + + // NULL-terminate with both a narrow and wide zero. + *((char *)bstr + len) = '\0'; + *(WCHAR *)((char *)bstr + ((len + 1) & ~1)) = 0; + } + + return bstr; +} + +/*** +*void SysFreeString(BSTR) +*Purpose: +* Free the given BSTR. +* +*Entry: +* bstr = the BSTR to free +* +*Exit: +* None +* +***********************************************************************/ +STDAPI_(void) SysFreeString(BSTR bstr) +{ + if(bstr == NULL) + return; + free((BYTE *)bstr-sizeof(DWORD_PTR)); +} + +/*** +*unsigned int SysStringLen(BSTR) +*Purpose: +* return the length in characters of the given BSTR. +* +*Entry: +* bstr = the BSTR to return the length of +* +*Exit: +* return value = unsigned int, length in characters. +* +***********************************************************************/ +STDAPI_(unsigned int) +SysStringLen(BSTR bstr) +{ + if(bstr == NULL) + return 0; + return (unsigned int)((((DWORD FAR*)bstr)[-1]) / sizeof(OLECHAR)); +} + +/*** +*unsigned int SysStringByteLen(BSTR) +*Purpose: +* return the size in bytes of the given BSTR. +* +*Entry: +* bstr = the BSTR to return the size of +* +*Exit: +* return value = unsigned int, size in bytes. +* +***********************************************************************/ +STDAPI_(unsigned int) +SysStringByteLen(BSTR bstr) +{ + if(bstr == NULL) + return 0; + return (unsigned int)(((DWORD FAR*)bstr)[-1]); +} + +extern "C" HRESULT +ErrStringCopy(BSTR bstrSource, BSTR FAR *pbstrOut) +{ + if (bstrSource == NULL) { + *pbstrOut = NULL; + return NOERROR; + } + if ((*pbstrOut = SysAllocStringLen(bstrSource, + SysStringLen(bstrSource))) == NULL) + return E_OUTOFMEMORY; + + return NOERROR; +} + +/*** +*PRIVATE HRESULT ErrSysAllocString(char*, BSTR*) +*Purpose: +* This is an implementation of SysAllocString that check for the +* NULL return value and return the corresponding error - E_OUTOFMEMORY. +* +* This is simply a convenience, and this routine is only used +* internally by the oledisp component. +* +*Entry: +* psz = the source string +* +*Exit: +* return value = HRESULT +* S_OK +* E_OUTOFMEMORY +* +* *pbstrOut = the newly allocated BSTR +* +***********************************************************************/ +extern "C" HRESULT +ErrSysAllocString(const OLECHAR FAR* psz, BSTR FAR* pbstrOut) +{ + if(psz == NULL){ + *pbstrOut = NULL; + return NOERROR; + } + + if((*pbstrOut = SysAllocString(psz)) == NULL) + return E_OUTOFMEMORY; + + return NOERROR; +} diff --git a/src/coreclr/palrt/coguid.cpp b/src/coreclr/palrt/coguid.cpp new file mode 100644 index 00000000000..8a91d8fa864 --- /dev/null +++ b/src/coreclr/palrt/coguid.cpp @@ -0,0 +1,192 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// + +// +// =========================================================================== +// File: coguid.cpp +// +// misc guid functions for PALRT +// =========================================================================== + +#include "common.h" + +STDAPI_(int) StringFromGUID2(REFGUID rguid, LPOLESTR lptsz, int cchMax) +{ + if (cchMax < 39) + return 0; + + return swprintf_s(lptsz, cchMax, W("{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}"), + rguid.Data1, rguid.Data2, rguid.Data3, + rguid.Data4[0], rguid.Data4[1], + rguid.Data4[2], rguid.Data4[3], + rguid.Data4[4], rguid.Data4[5], + rguid.Data4[6], rguid.Data4[7]) + 1; +} + +static BOOL wUUIDFromString(LPCWSTR lpsz, GUID * pguid); +static BOOL wGUIDFromString(LPCWSTR lpsz, GUID * pguid); + +static BOOL HexStringToDword(LPCWSTR FAR& lpsz, DWORD FAR& Value, + int cDigits, WCHAR chDelim); + +//+------------------------------------------------------------------------- +// +// Function: IIDFromString +// +// Synopsis: converts string {...} form int guid +// +// Arguments: [lpsz] - ptr to buffer for results +// [lpclsid] - the guid to convert +// +// Returns: NOERROR +// CO_E_CLASSSTRING +// +//-------------------------------------------------------------------------- +STDAPI IIDFromString(LPWSTR lpsz, CLSID * lpclsid) +{ + if (lpsz == NULL) + { + *lpclsid = CLSID_NULL; + return NOERROR; + } + + if (*lpsz == 0) + { + return(CO_E_CLASSSTRING); + } + + return wGUIDFromString(lpsz,lpclsid) + ? NOERROR : CO_E_CLASSSTRING; +} + +//+------------------------------------------------------------------------- +// +// Function: wGUIDFromString (internal) +// +// Synopsis: Parse GUID such as {00000000-0000-0000-0000-000000000000} +// +// Arguments: [lpsz] - the guid string to convert +// [pguid] - guid to return +// +// Returns: TRUE if successful +// +//-------------------------------------------------------------------------- +static BOOL wGUIDFromString(LPCWSTR lpsz, GUID * pguid) +{ + if (*lpsz++ != '{' ) + return FALSE; + + if (wUUIDFromString(lpsz, pguid) != TRUE) + return FALSE; + + lpsz +=36; + + if (*lpsz++ != '}' ) + return FALSE; + + if (*lpsz != '\0') + return FALSE; + + return TRUE; +} + +//+------------------------------------------------------------------------- +// +// Function: wUUIDFromString (internal) +// +// Synopsis: Parse UUID such as 00000000-0000-0000-0000-000000000000 +// +// Arguments: [lpsz] - Supplies the UUID string to convert +// [pguid] - Returns the GUID. +// +// Returns: TRUE if successful +// +//-------------------------------------------------------------------------- +static BOOL wUUIDFromString(LPCWSTR lpsz, GUID * pguid) +{ + DWORD dw; + + if (!HexStringToDword(lpsz, pguid->Data1, sizeof(DWORD)*2, '-')) + return FALSE; + + if (!HexStringToDword(lpsz, dw, sizeof(WORD)*2, '-')) + return FALSE; + pguid->Data2 = (WORD)dw; + + if (!HexStringToDword(lpsz, dw, sizeof(WORD)*2, '-')) + return FALSE; + pguid->Data3 = (WORD)dw; + + if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, 0)) + return FALSE; + pguid->Data4[0] = (BYTE)dw; + + if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, '-')) + return FALSE; + pguid->Data4[1] = (BYTE)dw; + + if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, 0)) + return FALSE; + pguid->Data4[2] = (BYTE)dw; + + if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, 0)) + return FALSE; + pguid->Data4[3] = (BYTE)dw; + + if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, 0)) + return FALSE; + pguid->Data4[4] = (BYTE)dw; + + if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, 0)) + return FALSE; + pguid->Data4[5] = (BYTE)dw; + + if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, 0)) + return FALSE; + pguid->Data4[6] = (BYTE)dw; + + if (!HexStringToDword(lpsz, dw, sizeof(BYTE)*2, 0)) + return FALSE; + pguid->Data4[7] = (BYTE)dw; + + return TRUE; +} + +//+------------------------------------------------------------------------- +// +// Function: HexStringToDword (private) +// +// Synopsis: scan lpsz for a number of hex digits (at most 8); update lpsz +// return value in Value; check for chDelim; +// +// Arguments: [lpsz] - the hex string to convert +// [Value] - the returned value +// [cDigits] - count of digits +// +// Returns: TRUE for success +// +//-------------------------------------------------------------------------- +static BOOL HexStringToDword(LPCWSTR FAR& lpsz, DWORD FAR& Value, + int cDigits, WCHAR chDelim) +{ + int Count; + + Value = 0; + for (Count = 0; Count < cDigits; Count++, lpsz++) + { + if (*lpsz >= '0' && *lpsz <= '9') + Value = (Value << 4) + *lpsz - '0'; + else if (*lpsz >= 'A' && *lpsz <= 'F') + Value = (Value << 4) + *lpsz - 'A' + 10; + else if (*lpsz >= 'a' && *lpsz <= 'f') + Value = (Value << 4) + *lpsz - 'a' + 10; + else + return(FALSE); + } + + if (chDelim != 0) + return *lpsz++ == chDelim; + else + return TRUE; +} diff --git a/src/coreclr/palrt/comem.cpp b/src/coreclr/palrt/comem.cpp new file mode 100644 index 00000000000..e56e720cc80 --- /dev/null +++ b/src/coreclr/palrt/comem.cpp @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// + +// +// =========================================================================== +// File: comem.cpp +// +// =========================================================================== + +#include "common.h" + +STDAPI_(LPVOID) CoTaskMemAlloc(SIZE_T cb) +{ + return malloc(cb); +} + +STDAPI_(void) CoTaskMemFree(LPVOID pv) +{ + free(pv); +} diff --git a/src/coreclr/palrt/common.h b/src/coreclr/palrt/common.h new file mode 100644 index 00000000000..684c134abed --- /dev/null +++ b/src/coreclr/palrt/common.h @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +//***************************************************************************** +// common.h +// + +// +// Common include file for the palrt code. +//***************************************************************************** + +#ifndef _COMMON_H_ +#define _COMMON_H_ + +#include <switches.h> +#include <winwrap.h> +#include "shlwapip.h" +#endif // _COMMON_H_ diff --git a/src/coreclr/palrt/guid.cpp b/src/coreclr/palrt/guid.cpp new file mode 100644 index 00000000000..68cc157d91c --- /dev/null +++ b/src/coreclr/palrt/guid.cpp @@ -0,0 +1,47 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// + +// +// =========================================================================== +// File: guid.cpp +// +// PALRT guids +// =========================================================================== + +#define INITGUID +#include <guiddef.h> + +// These are GUIDs and IIDs that would normally be provided by the system via uuid.lib, +// and that the PALRT exposes through headers. + +DEFINE_GUID(GUID_NULL, 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); +DEFINE_GUID(IID_IUnknown, 0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); +DEFINE_GUID(IID_IClassFactory, 0x00000001, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); + + +// objidl.idl +DEFINE_GUID(IID_ISequentialStream, 0x0c733a30, 0x2a1c, 0x11ce, 0xad, 0xe5, 0x00, 0xaa, 0x00, 0x44, 0x77, 0x3d); +DEFINE_GUID(IID_IStream, 0x0000000c, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); + +// Create a random guid based on the https://www.ietf.org/rfc/rfc4122.txt +STDAPI +CoCreateGuid(OUT GUID * pguid) +{ + PAL_Random(pguid, sizeof(GUID)); + + static const USHORT VersionMask = 0xF000; + static const USHORT RandomGuidVersion = 0x4000; + + static const BYTE ClockSeqHiAndReservedMask = 0xC0; + static const BYTE ClockSeqHiAndReservedValue = 0x80; + + // Modify bits indicating the type of the GUID + + // time_hi_and_version + pguid->Data3 = (pguid->Data3 & ~VersionMask) | RandomGuidVersion; + // clock_seq_hi_and_reserved + pguid->Data4[0] = (pguid->Data4[0] & ~ClockSeqHiAndReservedMask) | ClockSeqHiAndReservedValue; + + return S_OK; +} diff --git a/src/coreclr/palrt/memorystream.cpp b/src/coreclr/palrt/memorystream.cpp new file mode 100644 index 00000000000..0ed06547f3b --- /dev/null +++ b/src/coreclr/palrt/memorystream.cpp @@ -0,0 +1,316 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// + +// +// =========================================================================== +// File: memorystream.cpp +// +// =========================================================================== +/*++ + +Abstract: + + in memory stream + + + + +Revision History: + +--*/ + +#include "common.h" + +#include "objidl.h" + +class MemoryStream : public IStream +{ + LONG m_cRef; // QI refcount + ULONG m_nPos; // the current position in the stream + ULONG m_nSize; // the current size of the stream + ULONG m_nData; // the size of the allocated data storage, can be < m_nSize + BYTE* m_pData; // the data storage + +private: + HRESULT Ensure(ULONG nNewData) + { + if (nNewData > m_nData) + { + // apply some heurestic for growing + ULONG n = m_nData; + + // grow 2x for smaller sizes, 1.25x for bigger sizes + n = min(2 * n, n + n / 4 + 0x100000); + + // don't allocate tiny chunks + n = max(n, 0x100); + + // compare with the hard limit + nNewData = max(n, nNewData); + } + else + if (nNewData > m_nData / 4) + { + // shrinking but it is not worth it + return S_OK; + } + + BYTE * pNewData = (BYTE*)realloc(m_pData, nNewData); + if (pNewData == NULL && nNewData != 0) + return E_OUTOFMEMORY; + + m_nData = nNewData; + m_pData = pNewData; + return S_OK; + } + +public: + MemoryStream() + { + m_cRef = 1; + m_nPos = 0; + m_nSize = 0; + m_nData = 0; + m_pData = NULL; + } + +#ifdef __GNUC__ + virtual +#endif + ~MemoryStream() + { + free(m_pData); + } + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void **ppvObject) + { + if (riid == IID_IStream || + riid == IID_ISequentialStream || + riid == IID_IUnknown) + { + InterlockedIncrement(&m_cRef); + *ppvObject = this; + return S_OK; + } + else + { + *ppvObject = NULL; + return E_NOINTERFACE; + } + } + + ULONG STDMETHODCALLTYPE AddRef() + { + return InterlockedIncrement(&m_cRef); + } + + ULONG STDMETHODCALLTYPE Release() + { + LONG cRef = InterlockedDecrement(&m_cRef); + if (cRef == 0) + delete this; + return cRef; + } + + HRESULT STDMETHODCALLTYPE Read( + void *pv, + ULONG cb, + ULONG *pcbRead) + { + ULONG nData; + ULONG nNewPos = m_nPos + cb; + + // check for overflow + if (nNewPos < cb) + return STG_E_INVALIDFUNCTION; + + // compare with the actual size + nNewPos = min(nNewPos, m_nSize); + + // compare with the data available + nData = min(nNewPos, m_nData); + + // copy the data over + if (nData > m_nPos) + memcpy(pv, m_pData + m_nPos, nData - m_nPos); + + // fill the rest with zeros + if (nNewPos > nData) + memset((BYTE*)pv + (nData - m_nPos), 0, nNewPos - nData); + + cb = nNewPos - m_nPos; + m_nPos = nNewPos; + + if (pcbRead) + *pcbRead = cb; + + return S_OK; + } + + HRESULT STDMETHODCALLTYPE Write( + const void *pv, + ULONG cb, + ULONG *pcbWritten) + { + ULONG nNewPos = m_nPos + cb; + + // check for overflow + if (nNewPos < cb) + return STG_E_INVALIDFUNCTION; + + // ensure the space + if (nNewPos > m_nData) + { + HRESULT hr = Ensure(nNewPos); + if (FAILED(hr)) return hr; + } + + // copy the data over + memcpy(m_pData + m_nPos, pv, cb); + + m_nPos = nNewPos; + if (m_nPos > m_nSize) + m_nSize = m_nPos; + + if (pcbWritten) + *pcbWritten = cb; + + return S_OK; + } + + HRESULT STDMETHODCALLTYPE Seek( + LARGE_INTEGER dlibMove, + DWORD dwOrigin, + ULARGE_INTEGER *plibNewPosition) + { + ULONG lStartPos; + LONGLONG lNewPos; + + switch (dwOrigin) + { + case STREAM_SEEK_SET: + lStartPos = 0; + break; + case STREAM_SEEK_CUR: + lStartPos = m_nPos; + break; + case STREAM_SEEK_END: + lStartPos = m_nSize; + break; + default: + return STG_E_INVALIDFUNCTION; + } + + lNewPos = lStartPos + dlibMove.QuadPart; + + // it is an error to seek before the beginning of the stream + if (lNewPos < 0) + return STG_E_INVALIDFUNCTION; + + // It is not, however, an error to seek past the end of the stream + if (lNewPos > m_nSize) + { + ULARGE_INTEGER NewSize; + NewSize.QuadPart = lNewPos; + + HRESULT hr = SetSize(NewSize); + if (FAILED(hr)) return hr; + } + + m_nPos = (ULONG)lNewPos; + + if (plibNewPosition != NULL) + plibNewPosition->QuadPart = m_nPos; + + return S_OK; + } + + HRESULT STDMETHODCALLTYPE SetSize( + ULARGE_INTEGER libNewSize) + { + if (libNewSize.u.HighPart != 0) + return STG_E_INVALIDFUNCTION; + + m_nSize = libNewSize.u.LowPart; + + // free the space if we are shrinking + if (m_nSize < m_nData) + Ensure(m_nSize); + + return S_OK; + } + + HRESULT STDMETHODCALLTYPE CopyTo( + IStream *pstm, + ULARGE_INTEGER cb, + ULARGE_INTEGER *pcbRead, + ULARGE_INTEGER *pcbWritten) + { + _ASSERTE(false); + return E_NOTIMPL; + } + + HRESULT STDMETHODCALLTYPE Commit( + DWORD grfCommitFlags) + { + _ASSERTE(false); + return E_NOTIMPL; + } + + HRESULT STDMETHODCALLTYPE Revert() + { + _ASSERTE(false); + return E_NOTIMPL; + } + + HRESULT STDMETHODCALLTYPE LockRegion( + ULARGE_INTEGER libOffset, + ULARGE_INTEGER cb, + DWORD dwLockType) + { + _ASSERTE(false); + return E_NOTIMPL; + } + + HRESULT STDMETHODCALLTYPE UnlockRegion( + ULARGE_INTEGER libOffset, + ULARGE_INTEGER cb, + DWORD dwLockType) + { + _ASSERTE(false); + return E_NOTIMPL; + } + + HRESULT STDMETHODCALLTYPE Stat( + STATSTG *pstatstg, + DWORD grfStatFlag) + { + memset(pstatstg, 0, sizeof(STATSTG)); + pstatstg->cbSize.QuadPart = m_nSize; + return S_OK; + } + + HRESULT STDMETHODCALLTYPE Clone( + IStream **ppstm) + { + _ASSERTE(false); + return E_NOTIMPL; + } +}; + +STDAPI CreateStreamOnHGlobal(PVOID hGlobal, BOOL fDeleteOnRelease, IStream** ppstm) +{ + MemoryStream* pStream; + + if (hGlobal != NULL) return E_NOTIMPL; + _ASSERTE(fDeleteOnRelease == TRUE); + + pStream = new MemoryStream; + if (pStream == NULL) return E_OUTOFMEMORY; + + *ppstm = pStream; + return S_OK; +} diff --git a/src/coreclr/palrt/path.cpp b/src/coreclr/palrt/path.cpp new file mode 100644 index 00000000000..7e0d2279f4a --- /dev/null +++ b/src/coreclr/palrt/path.cpp @@ -0,0 +1,646 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// + +// +// =========================================================================== +// File: path.cpp +// +// Path APIs ported from shlwapi (especially for Fusion) +// =========================================================================== + +#include "common.h" +#include "strsafe.h" + + +#define CH_SLASH W('/') +#define CH_WHACK W('\\') + +// +// Inline function to check for a double-backslash at the +// beginning of a string +// + +static __inline BOOL DBL_BSLASH(LPCWSTR psz) +{ + return (psz[0] == W('\\') && psz[1] == W('\\')); +} + +// +// Inline function to check for a path separator character. +// + +static __inline BOOL IsPathSeparator(WCHAR ch) +{ + return (ch == CH_SLASH || ch == CH_WHACK); +} + +__inline BOOL ChrCmpW_inline(WCHAR w1, WCHAR wMatch) +{ + return(!(w1 == wMatch)); +} + +STDAPI_(LPWSTR) StrRChrW(LPCWSTR lpStart, LPCWSTR lpEnd, WCHAR wMatch) +{ + LPCWSTR lpFound = NULL; + + RIPMSG(lpStart && IS_VALID_STRING_PTRW(lpStart, -1), "StrRChrW: caller passed bad lpStart"); + RIPMSG(!lpEnd || lpEnd <= lpStart + wcslen(lpStart), "StrRChrW: caller passed bad lpEnd"); + // don't need to check for NULL lpStart + + if (!lpEnd) + lpEnd = lpStart + wcslen(lpStart); + + for ( ; lpStart < lpEnd; lpStart++) + { + if (!ChrCmpW_inline(*lpStart, wMatch)) + lpFound = lpStart; + } + return ((LPWSTR)lpFound); +} + + +// check if a path is a root +// +// returns: +// TRUE +// "\" "X:\" "\\" "\\foo" "\\foo\bar" +// +// FALSE for others including "\\foo\bar\" (!) +// +STDAPI_(BOOL) PathIsRootW(LPCWSTR pPath) +{ + RIPMSG(pPath && IS_VALID_STRING_PTR(pPath, -1), "PathIsRoot: caller passed bad pPath"); + + if (!pPath || !*pPath) + { + return FALSE; + } + + if (!lstrcmpiW(pPath + 1, W(":\\"))) + { + return TRUE; // "X:\" case + } + + if (IsPathSeparator(*pPath) && (*(pPath + 1) == 0)) + { + return TRUE; // "/" or "\" case + } + + if (DBL_BSLASH(pPath)) // smells like UNC name + { + LPCWSTR p; + int cBackslashes = 0; + + for (p = pPath + 2; *p; p++) + { + if (*p == W('\\')) + { + // + // return FALSE for "\\server\share\dir" + // so just check if there is more than one slash + // + // "\\server\" without a share name causes + // problems for WNet APIs. we should return + // FALSE for this as well + // + if ((++cBackslashes > 1) || !*(p+1)) + return FALSE; + } + } + // end of string with only 1 more backslash + // must be a bare UNC, which looks like a root dir + return TRUE; + } + return FALSE; +} + +/* +// rips the last part of the path off including the backslash +// C:\foo -> C:\ +// C:\foo\bar -> C:\foo +// C:\foo\ -> C:\foo +// \\x\y\x -> \\x\y +// \\x\y -> \\x +// \\x -> \\ (Just the double slash!) +// \foo -> \ (Just the slash!) +// +// in/out: +// pFile fully qualified path name +// returns: +// TRUE we stripped something +// FALSE didn't strip anything (root directory case) +// +*/ +STDAPI_(BOOL) PathRemoveFileSpecW(LPWSTR pFile) +{ + RIPMSG(pFile && IS_VALID_STRING_PTR(pFile, -1), "PathRemoveFileSpec: caller passed bad pFile"); + + if (pFile) + { + LPWSTR pT; + LPWSTR pT2 = pFile; + + for (pT = pT2; *pT2; pT2++) + { + if (IsPathSeparator(*pT2)) + { + pT = pT2; // last "\" found, (we will strip here) + } + else if (*pT2 == W(':')) // skip ":\" so we don't + { + if (IsPathSeparator(pT2[1])) // strip the "\" from "C:\" + { + pT2++; + } + pT = pT2 + 1; + } + } + + if (*pT == 0) + { + // didn't strip anything + return FALSE; + } + else if (((pT == pFile) && IsPathSeparator(*pT)) || // is it the "\foo" case? + ((pT == pFile+1) && (*pT == CH_WHACK && *pFile == CH_WHACK))) // or the "\\bar" case? + { + // Is it just a '\'? + if (*(pT+1) != W('\0')) + { + // Nope. + *(pT+1) = W('\0'); + return TRUE; // stripped something + } + else + { + // Yep. + return FALSE; + } + } + else + { + *pT = 0; + return TRUE; // stripped something + } + } + return FALSE; +} + +// +// Return a pointer to the end of the next path component in the string. +// ie return a pointer to the next backslash or terminating NULL. +// +LPCWSTR GetPCEnd(LPCWSTR lpszStart) +{ + LPCWSTR lpszEnd; + LPCWSTR lpszSlash; + + lpszEnd = StrChr(lpszStart, CH_WHACK); + lpszSlash = StrChr(lpszStart, CH_SLASH); + if ((lpszSlash && lpszSlash < lpszEnd) || + !lpszEnd) + { + lpszEnd = lpszSlash; + } + if (!lpszEnd) + { + lpszEnd = lpszStart + wcslen(lpszStart); + } + + return lpszEnd; +} + +// +// Given a pointer to the end of a path component, return a pointer to +// its beginning. +// ie return a pointer to the previous backslash (or start of the string). +// +LPCWSTR PCStart(LPCWSTR lpszStart, LPCWSTR lpszEnd) +{ + LPCWSTR lpszBegin = StrRChrW(lpszStart, lpszEnd, CH_WHACK); + LPCWSTR lpszSlash = StrRChrW(lpszStart, lpszEnd, CH_SLASH); + if (lpszSlash > lpszBegin) + { + lpszBegin = lpszSlash; + } + if (!lpszBegin) + { + lpszBegin = lpszStart; + } + return lpszBegin; +} + +// +// Fix up a few special cases so that things roughly make sense. +// +void NearRootFixups(LPWSTR lpszPath, BOOL fUNC) +{ + // Check for empty path. + if (lpszPath[0] == W('\0')) + { + // Fix up. +#ifndef TARGET_UNIX + lpszPath[0] = CH_WHACK; +#else + lpszPath[0] = CH_SLASH; +#endif + lpszPath[1] = W('\0'); + } + // Check for missing slash. + if (lpszPath[1] == W(':') && lpszPath[2] == W('\0')) + { + // Fix up. + lpszPath[2] = W('\\'); + lpszPath[3] = W('\0'); + } + // Check for UNC root. + if (fUNC && lpszPath[0] == W('\\') && lpszPath[1] == W('\0')) + { + // Fix up. + //lpszPath[0] = W('\\'); // already checked in if guard + lpszPath[1] = W('\\'); + lpszPath[2] = W('\0'); + } +} + +/*---------------------------------------------------------- +Purpose: Canonicalize a path. + +Returns: +Cond: -- +*/ +STDAPI_(BOOL) PathCanonicalizeW(LPWSTR lpszDst, LPCWSTR lpszSrc) +{ + LPCWSTR lpchSrc; + LPCWSTR lpchPCEnd; // Pointer to end of path component. + LPWSTR lpchDst; + BOOL fUNC; + int cchPC; + + RIPMSG(lpszDst && IS_VALID_WRITE_BUFFER(lpszDst, WCHAR, MAX_PATH), "PathCanonicalize: caller passed bad lpszDst"); + RIPMSG(lpszSrc && IS_VALID_STRING_PTR(lpszSrc, -1), "PathCanonicalize: caller passed bad lpszSrc"); + RIPMSG(lpszDst != lpszSrc, "PathCanonicalize: caller passed the same buffer for lpszDst and lpszSrc"); + + if (!lpszDst || !lpszSrc) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + *lpszDst = W('\0'); + + fUNC = PathIsUNCW(lpszSrc); // Check for UNCness. + + // Init. + lpchSrc = lpszSrc; + lpchDst = lpszDst; + + while (*lpchSrc) + { + lpchPCEnd = GetPCEnd(lpchSrc); + cchPC = (int) (lpchPCEnd - lpchSrc)+1; + + if (cchPC == 1 && IsPathSeparator(*lpchSrc)) // Check for slashes. + { + // Just copy them. +#ifndef TARGET_UNIX + *lpchDst = CH_WHACK; +#else + *lpchDst = CH_SLASH; +#endif + lpchDst++; + lpchSrc++; + } + else if (cchPC == 2 && *lpchSrc == W('.')) // Check for dots. + { + // Skip it... + // Are we at the end? + if (*(lpchSrc+1) == W('\0')) + { + lpchSrc++; + + // remove the last slash we copied (if we've copied one), but don't make a mal-formed root + if ((lpchDst > lpszDst) && !PathIsRootW(lpszDst)) + lpchDst--; + } + else + { + lpchSrc += 2; + } + } + else if (cchPC == 3 && *lpchSrc == W('.') && *(lpchSrc + 1) == W('.')) // Check for dot dot. + { + // make sure we aren't already at the root + if (!PathIsRootW(lpszDst)) + { + // Go up... Remove the previous path component. + lpchDst = (LPWSTR)PCStart(lpszDst, lpchDst - 1); + } + else + { + // When we can't back up, skip the trailing backslash + // so we don't copy one again. (C:\..\FOO would otherwise + // turn into C:\\FOO). + if (IsPathSeparator(*(lpchSrc + 2))) + { + lpchSrc++; + } + } + + // skip ".." + lpchSrc += 2; + } + else // Everything else + { + // Just copy it. + int cchRemainingBuffer = MAX_PATH - (lpszDst - lpchDst); + StringCchCopyNW(lpchDst, cchRemainingBuffer, lpchSrc, cchPC); + lpchDst += cchPC - 1; + lpchSrc += cchPC - 1; + } + + // Keep everything nice and tidy. + *lpchDst = W('\0'); + } + + // Check for weirdo root directory stuff. + NearRootFixups(lpszDst, fUNC); + + return TRUE; +} + +// Modifies: +// pszRoot +// +// Returns: +// TRUE if a drive root was found +// FALSE otherwise +// +STDAPI_(BOOL) PathStripToRootW(LPWSTR pszRoot) +{ + RIPMSG(pszRoot && IS_VALID_STRING_PTR(pszRoot, -1), "PathStripToRoot: caller passed bad pszRoot"); + + if (pszRoot) + { + while (!PathIsRootW(pszRoot)) + { + if (!PathRemoveFileSpecW(pszRoot)) + { + // If we didn't strip anything off, + // must be current drive + return FALSE; + } + } + return TRUE; + } + return FALSE; +} + + + +/*---------------------------------------------------------- +Purpose: Concatenate lpszDir and lpszFile into a properly formed + path and canonicalize any relative path pieces. + + lpszDest and lpszFile can be the same buffer + lpszDest and lpszDir can be the same buffer + +Returns: pointer to lpszDest +*/ +STDAPI_(LPWSTR) PathCombineW(LPWSTR lpszDest, LPCWSTR lpszDir, LPCWSTR lpszFile) +{ +#ifdef DEBUG + RIPMSG(lpszDest && IS_VALID_WRITE_BUFFER(lpszDest, TCHAR, MAX_LONGPATH), "PathCombine: caller passed bad lpszDest"); + RIPMSG(!lpszDir || IS_VALID_STRING_PTR(lpszDir, -1), "PathCombine: caller passed bad lpszDir"); + RIPMSG(!lpszFile || IS_VALID_STRING_PTR(lpszFile, -1), "PathCombine: caller passed bad lpszFile"); + RIPMSG(lpszDir || lpszFile, "PathCombine: caller neglected to pass lpszDir or lpszFile"); +#endif // DEBUG + + + if (lpszDest) + { + TCHAR szTemp[MAX_LONGPATH]; + LPWSTR pszT; + + *szTemp = W('\0'); + + if (lpszDir && *lpszDir) + { + if (!lpszFile || *lpszFile==W('\0')) + { + // lpszFile is empty + StringCchCopyNW(szTemp, ARRAYSIZE(szTemp), lpszDir, ARRAYSIZE(szTemp)); + } + else if (PathIsRelativeW(lpszFile)) + { + StringCchCopyNW(szTemp, ARRAYSIZE(szTemp), lpszDir, ARRAYSIZE(szTemp)); + pszT = PathAddBackslashW(szTemp); + if (pszT) + { + size_t iRemaining = ARRAYSIZE(szTemp) - (pszT - szTemp); + + if (wcslen(lpszFile) < iRemaining) + { + StringCchCopyNW(pszT, iRemaining, lpszFile, iRemaining); + } + else + { + *szTemp = W('\0'); + } + } + else + { + *szTemp = W('\0'); + } + } + else if (IsPathSeparator(*lpszFile) && !PathIsUNCW(lpszFile)) + { + StringCchCopyNW(szTemp, ARRAYSIZE(szTemp), lpszDir, ARRAYSIZE(szTemp)); + // FEATURE: Note that we do not check that an actual root is returned; + // it is assumed that we are given valid parameters + PathStripToRootW(szTemp); + + pszT = PathAddBackslashW(szTemp); + if (pszT) + { + // Skip the backslash when copying + // Note: We don't support strings longer than 4GB, but that's + // okay because we already fail at MAX_PATH + int iRemaining = (int)(ARRAYSIZE(szTemp) - (pszT - szTemp)); + StringCchCopyNW(pszT, iRemaining, lpszFile+1, iRemaining); + } + else + { + *szTemp = W('\0'); + } + } + else + { + // already fully qualified file part + StringCchCopyNW(szTemp, ARRAYSIZE(szTemp), lpszFile, ARRAYSIZE(szTemp)); + } + } + else if (lpszFile && *lpszFile) + { + // no dir just use file. + StringCchCopyNW(szTemp, ARRAYSIZE(szTemp), lpszFile, ARRAYSIZE(szTemp)); + } + + // + // if szTemp has something in it we succeeded. Also if szTemp is empty and + // the input strings are empty we succeed and PathCanonicalize() will + // return "\" + // + if (*szTemp || ((lpszDir || lpszFile) && !((lpszDir && *lpszDir) || (lpszFile && *lpszFile)))) + { + PathCanonicalizeW(lpszDest, szTemp); // this deals with .. and . stuff + // returns "\" on empty szTemp + } + else + { + *lpszDest = W('\0'); // set output buffer to empty string. + lpszDest = NULL; // return failure. + } + } + + return lpszDest; +} + +// add a backslash to a qualified path +// +// in: +// lpszPath path (A:, C:\foo, etc) +// +// out: +// lpszPath A:\, C:\foo\ ; +// +// returns: +// pointer to the NULL that terminates the path +// +STDAPI_(LPWSTR) PathAddBackslashW(LPWSTR lpszPath) +{ + LPWSTR lpszRet = NULL; + + RIPMSG(lpszPath && IS_VALID_STRING_PTR(lpszPath, -1), "PathAddBackslash: caller passed bad lpszPath"); + + if (lpszPath) + { + size_t ichPath = wcslen(lpszPath); + LPWSTR lpszEnd = lpszPath + ichPath; + + if (ichPath) + { + + // Get the end of the source directory + switch(*(lpszEnd-1)) + { + case CH_SLASH: + case CH_WHACK: + break; + + default: + // try to keep us from tromping over MAX_PATH in size. + // if we find these cases, return NULL. Note: We need to + // check those places that call us to handle their GP fault + // if they try to use the NULL! + if (ichPath >= (MAX_PATH - 2)) // -2 because ichPath doesn't include NULL, and we're adding a CH_WHACK. + { + return(NULL); + } + + *lpszEnd++ = CH_WHACK; + *lpszEnd = W('\0'); + } + } + + lpszRet = lpszEnd; + } + + return lpszRet; +} + + + + +//--------------------------------------------------------------------------- +// Returns TRUE if the given string is a UNC path. +// +// TRUE +// "\\foo\bar" +// "\\foo" <- careful +// "\\" +// FALSE +// "\foo" +// "foo" +// "c:\foo" +// +// +STDAPI_(BOOL) PathIsUNCW(LPCWSTR pszPath) +{ + RIPMSG(pszPath && IS_VALID_STRING_PTR(pszPath, -1), "PathIsUNC: caller passed bad pszPath"); + + if (pszPath) + { + return DBL_BSLASH(pszPath); + } + return FALSE; +} + + + + + +//--------------------------------------------------------------------------- +// Return TRUE if the path isn't absoulte. +// +// TRUE +// "foo.exe" +// ".\foo.exe" +// "..\boo\foo.exe" +// +// FALSE +// "\foo" +// "c:bar" <- be careful +// "c:\bar" +// "\\foo\bar" +// +STDAPI_(BOOL) PathIsRelativeW(LPCWSTR lpszPath) +{ + RIPMSG(lpszPath && IS_VALID_STRING_PTR(lpszPath, -1), "PathIsRelative: caller passed bad lpszPath"); + + if (!lpszPath || *lpszPath == 0) + { + // The NULL path is assumed relative + return TRUE; + } + + if (IsPathSeparator(lpszPath[0])) + { + // Does it begin with a slash ? + return FALSE; + } + else if (lpszPath[1] == W(':')) + { + // Does it begin with a drive and a colon ? + return FALSE; + } + else + { + // Probably relative. + return TRUE; + } +} + +// find the next slash or null terminator +LPWSTR StrSlash(LPCWSTR psz) +{ + for (; *psz && !IsPathSeparator(*psz); psz++); + + // Cast to a non-const string to mimic the behavior + // of wcschr/StrChr and strchr. + return (LPWSTR) psz; +} + + + diff --git a/src/coreclr/palrt/shlwapip.h b/src/coreclr/palrt/shlwapip.h new file mode 100644 index 00000000000..a34c923c346 --- /dev/null +++ b/src/coreclr/palrt/shlwapip.h @@ -0,0 +1,37 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// + +// +// =========================================================================== +// File: shlwapi.h +// +// Header for ported shlwapi stuff +// =========================================================================== + +#ifndef SHLWAPIP_H_INCLUDED +#define SHLWAPIP_H_INCLUDED + +#define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0])) +#define SIZECHARS(sz) (sizeof(sz)/sizeof(sz[0])) + +#define SIZEOF(x) sizeof(x) +#define PRIVATE +#define PUBLIC +#ifndef ASSERT +#define ASSERT _ASSERTE +#endif +#define AssertMsg(f,m) _ASSERTE(f) +#define RIP(f) _ASSERTE(f) +#define RIPMSG(f,m) _ASSERTE(f) + +#define IS_VALID_READ_BUFFER(p, t, n) (p != NULL) +#define IS_VALID_WRITE_BUFFER(p, t, n) (p != NULL) + +#define IS_VALID_READ_PTR(p, t) IS_VALID_READ_BUFFER(p, t, 1) +#define IS_VALID_WRITE_PTR(p, t) IS_VALID_WRITE_BUFFER(p, t, 1) + +#define IS_VALID_STRING_PTR(p, c) (p != NULL) +#define IS_VALID_STRING_PTRW(p, c) (p != NULL) + +#endif // ! SHLWAPIP_H_INCLUDED diff --git a/src/coreclr/palrt/variant.cpp b/src/coreclr/palrt/variant.cpp new file mode 100644 index 00000000000..f96d1defdd1 --- /dev/null +++ b/src/coreclr/palrt/variant.cpp @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// + +// +// =========================================================================== +// File: variant.cpp +// +// PALRT variant conversion functions +// =========================================================================== + +#include "common.h" + +/*** +*PUBLIC void VariantInit(VARIANT*) +*Purpose: +* Initialize the given VARIANT to VT_EMPTY. +* +*Entry: +* None +* +*Exit: +* return value = void +* +* pvarg = pointer to initialized VARIANT +* +***********************************************************************/ +STDAPI_(void) +VariantInit(VARIANT FAR* pvarg) +{ + V_VT(pvarg) = VT_EMPTY; +} |