diff --git a/.gitignore b/.gitignore
index a4bf388..aee64d5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,2 @@
-/bin
-/.settings
-/sound
+/cpp/Pipe/.settings
+/cpp/pipe/.settings
diff --git a/cpp/Pipe/.cproject b/cpp/Pipe/.cproject
new file mode 100644
index 0000000..7e01e41
--- /dev/null
+++ b/cpp/Pipe/.cproject
@@ -0,0 +1,154 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cpp/Pipe/.project b/cpp/Pipe/.project
new file mode 100644
index 0000000..511c69c
--- /dev/null
+++ b/cpp/Pipe/.project
@@ -0,0 +1,27 @@
+
+
+ Pipe
+
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.genmakebuilder
+ clean,full,incremental,
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder
+ full,incremental,
+
+
+
+
+
+ org.eclipse.cdt.core.cnature
+ org.eclipse.cdt.core.ccnature
+ org.eclipse.cdt.managedbuilder.core.managedBuildNature
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigNature
+
+
diff --git a/cpp/Pipe/include/strsafe.h b/cpp/Pipe/include/strsafe.h
new file mode 100644
index 0000000..061b3c4
--- /dev/null
+++ b/cpp/Pipe/include/strsafe.h
@@ -0,0 +1,6611 @@
+/******************************************************************
+* *
+* strsafe.h -- This module defines safer C library string *
+* routine replacements. These are meant to make C *
+* a bit more safe in reference to security and *
+* robustness *
+* *
+* Copyright (c) Microsoft Corp. All rights reserved. *
+* *
+******************************************************************/
+#ifndef _STRSAFE_H_INCLUDED_
+#define _STRSAFE_H_INCLUDED_
+#pragma once
+
+#include // for _vsnprintf, _vsnwprintf, getc, getwc
+#include // for memset
+#include // for va_start, etc.
+
+
+#ifndef _SIZE_T_DEFINED
+#ifdef _WIN64
+typedef unsigned __int64 size_t;
+#else
+typedef __w64 unsigned int size_t;
+#endif // !_WIN64
+#define _SIZE_T_DEFINED
+#endif // !_SIZE_T_DEFINED
+
+#if !defined(_WCHAR_T_DEFINED) && !defined(_NATIVE_WCHAR_T_DEFINED)
+typedef unsigned short wchar_t;
+#define _WCHAR_T_DEFINED
+#endif
+
+#ifndef _HRESULT_DEFINED
+#define _HRESULT_DEFINED
+typedef long HRESULT;
+#endif // !_HRESULT_DEFINED
+
+#ifndef SUCCEEDED
+#define SUCCEEDED(hr) ((HRESULT)(hr) >= 0)
+#endif
+
+#ifndef FAILED
+#define FAILED(hr) ((HRESULT)(hr) < 0)
+#endif
+
+#ifndef S_OK
+#define S_OK ((HRESULT)0x00000000L)
+#endif
+
+#ifdef __cplusplus
+#define _STRSAFE_EXTERN_C extern "C"
+#else
+#define _STRSAFE_EXTERN_C extern
+#endif
+
+// If you do not want to use these functions inline (and instead want to link w/ strsafe.lib), then
+// #define STRSAFE_LIB before including this header file.
+#if defined(STRSAFE_LIB)
+#define STRSAFEAPI _STRSAFE_EXTERN_C HRESULT __stdcall
+#pragma comment(lib, "strsafe.lib")
+#elif defined(STRSAFE_LIB_IMPL)
+#define STRSAFEAPI _STRSAFE_EXTERN_C HRESULT __stdcall
+#else
+#define STRSAFEAPI __inline HRESULT __stdcall
+#define STRSAFE_INLINE
+#endif
+
+// Some functions always run inline because they use stdin and we want to avoid building multiple
+// versions of strsafe lib depending on if you use msvcrt, libcmt, etc.
+#define STRSAFE_INLINE_API __inline HRESULT __stdcall
+
+// The user can request no "Cb" or no "Cch" fuctions, but not both!
+#if defined(STRSAFE_NO_CB_FUNCTIONS) && defined(STRSAFE_NO_CCH_FUNCTIONS)
+#error cannot specify both STRSAFE_NO_CB_FUNCTIONS and STRSAFE_NO_CCH_FUNCTIONS !!
+#endif
+
+// This should only be defined when we are building strsafe.lib
+#ifdef STRSAFE_LIB_IMPL
+#define STRSAFE_INLINE
+#endif
+
+
+// If both strsafe.h and ntstrsafe.h are included, only use definitions from one.
+#ifndef _NTSTRSAFE_H_INCLUDED_
+
+#define STRSAFE_MAX_CCH 2147483647 // max # of characters we support (same as INT_MAX)
+
+// Flags for controling the Ex functions
+//
+// STRSAFE_FILL_BYTE(0xFF) 0x000000FF // bottom byte specifies fill pattern
+#define STRSAFE_IGNORE_NULLS 0x00000100 // treat null as TEXT("") -- don't fault on NULL buffers
+#define STRSAFE_FILL_BEHIND_NULL 0x00000200 // fill in extra space behind the null terminator
+#define STRSAFE_FILL_ON_FAILURE 0x00000400 // on failure, overwrite pszDest with fill pattern and null terminate it
+#define STRSAFE_NULL_ON_FAILURE 0x00000800 // on failure, set *pszDest = TEXT('\0')
+#define STRSAFE_NO_TRUNCATION 0x00001000 // instead of returning a truncated result, copy/append nothing to pszDest and null terminate it
+
+#define STRSAFE_VALID_FLAGS (0x000000FF | STRSAFE_IGNORE_NULLS | STRSAFE_FILL_BEHIND_NULL | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION)
+
+// helper macro to set the fill character and specify buffer filling
+#define STRSAFE_FILL_BYTE(x) ((unsigned long)((x & 0x000000FF) | STRSAFE_FILL_BEHIND_NULL))
+#define STRSAFE_FAILURE_BYTE(x) ((unsigned long)((x & 0x000000FF) | STRSAFE_FILL_ON_FAILURE))
+
+#define STRSAFE_GET_FILL_PATTERN(dwFlags) ((int)(dwFlags & 0x000000FF))
+
+#endif // _NTSTRSAFE_H_INCLUDED_
+
+// STRSAFE error return codes
+//
+#define STRSAFE_E_INSUFFICIENT_BUFFER ((HRESULT)0x8007007AL) // 0x7A = 122L = ERROR_INSUFFICIENT_BUFFER
+#define STRSAFE_E_INVALID_PARAMETER ((HRESULT)0x80070057L) // 0x57 = 87L = ERROR_INVALID_PARAMETER
+#define STRSAFE_E_END_OF_FILE ((HRESULT)0x80070026L) // 0x26 = 38L = ERROR_HANDLE_EOF
+
+// prototypes for the worker functions
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCopyWorkerA(char* pszDest, size_t cchDest, const char* pszSrc);
+STRSAFEAPI StringCopyWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc);
+STRSAFEAPI StringCopyExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCopyExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCopyNWorkerA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc);
+STRSAFEAPI StringCopyNWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc);
+STRSAFEAPI StringCopyNExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, size_t cchSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCopyNExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, size_t cchSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCatWorkerA(char* pszDest, size_t cchDest, const char* pszSrc);
+STRSAFEAPI StringCatWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc);
+STRSAFEAPI StringCatExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCatExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCatNWorkerA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend);
+STRSAFEAPI StringCatNWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend);
+STRSAFEAPI StringCatNExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, size_t cchMaxAppend, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCatNExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, size_t cchMaxAppend, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringVPrintfWorkerA(char* pszDest, size_t cchDest, const char* pszFormat, va_list argList);
+STRSAFEAPI StringVPrintfWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, va_list argList);
+STRSAFEAPI StringVPrintfExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList);
+STRSAFEAPI StringVPrintfExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList);
+STRSAFEAPI StringLengthWorkerA(const char* psz, size_t cchMax, size_t* pcch);
+STRSAFEAPI StringLengthWorkerW(const wchar_t* psz, size_t cchMax, size_t* pcch);
+#endif // STRSAFE_INLINE
+
+#ifndef STRSAFE_LIB_IMPL
+// these functions are always inline
+STRSAFE_INLINE_API StringGetsExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFE_INLINE_API StringGetsExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+#endif
+
+#ifdef _NTSTRSAFE_H_INCLUDED_
+#pragma warning(push)
+#pragma warning(disable : 4995)
+#endif // _NTSTRSAFE_H_INCLUDED_
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI
+StringCchCopy(
+ OUT LPTSTR pszDest,
+ IN size_t cchDest,
+ IN LPCTSTR pszSrc
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strcpy'.
+ The size of the destination buffer (in characters) is a parameter and
+ this function will not write past the end of this buffer and it will
+ ALWAYS null terminate the destination buffer (unless it is zero length).
+
+ This routine is not a replacement for strncpy. That function will pad the
+ destination string with extra null termination characters if the count is
+ greater than the length of the source string, and it will fail to null
+ terminate the destination string if the source string length is greater
+ than or equal to the count. You can not blindly use this instead of strncpy:
+ it is common for code to use it to "patch" strings and you would introduce
+ errors if the code started null terminating in the middle of the string.
+
+ This function returns a hresult, and not a pointer. It returns
+ S_OK if the string was copied without truncation and null terminated,
+ otherwise it will return a failure code. In failure cases as much of
+ pszSrc will be copied to pszDest as possible, and pszDest will be null
+ terminated.
+
+Arguments:
+
+ pszDest - destination string
+
+ cchDest - size of destination buffer in characters.
+ length must be = (_tcslen(src) + 1) to hold all of the
+ source including the null terminator
+
+ pszSrc - source string which must be null terminated
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL. See StringCchCopyEx if you require
+ the handling of NULL values.
+
+Return Value:
+
+ S_OK - if there was source data and it was all copied and the
+ resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the copy
+ operation failed due to insufficient space. When this
+ error occurs, the destination buffer is modified to
+ contain a truncated version of the ideal result and is
+ null terminated. This is useful for situations where
+ truncation is ok
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function.
+
+--*/
+
+STRSAFEAPI StringCchCopyA(char* pszDest, size_t cchDest, const char* pszSrc);
+STRSAFEAPI StringCchCopyW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc);
+#ifdef UNICODE
+#define StringCchCopy StringCchCopyW
+#else
+#define StringCchCopy StringCchCopyA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchCopyA(char* pszDest, size_t cchDest, const char* pszSrc)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyWorkerA(pszDest, cchDest, pszSrc);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCchCopyW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyWorkerW(pszDest, cchDest, pszSrc);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI
+StringCbCopy(
+ OUT LPTSTR pszDest,
+ IN size_t cbDest,
+ IN LPCTSTR pszSrc
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strcpy'.
+ The size of the destination buffer (in bytes) is a parameter and this
+ function will not write past the end of this buffer and it will ALWAYS
+ null terminate the destination buffer (unless it is zero length).
+
+ This routine is not a replacement for strncpy. That function will pad the
+ destination string with extra null termination characters if the count is
+ greater than the length of the source string, and it will fail to null
+ terminate the destination string if the source string length is greater
+ than or equal to the count. You can not blindly use this instead of strncpy:
+ it is common for code to use it to "patch" strings and you would introduce
+ errors if the code started null terminating in the middle of the string.
+
+ This function returns a hresult, and not a pointer. It returns
+ S_OK if the string was copied without truncation and null terminated,
+ otherwise it will return a failure code. In failure cases as much of pszSrc
+ will be copied to pszDest as possible, and pszDest will be null terminated.
+
+Arguments:
+
+ pszDest - destination string
+
+ cbDest - size of destination buffer in bytes.
+ length must be = ((_tcslen(src) + 1) * sizeof(TCHAR)) to
+ hold all of the source including the null terminator
+
+ pszSrc - source string which must be null terminated
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL. See StringCbCopyEx if you require
+ the handling of NULL values.
+
+Return Value:
+
+ S_OK - if there was source data and it was all copied and the
+ resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the copy
+ operation failed due to insufficient space. When this
+ error occurs, the destination buffer is modified to
+ contain a truncated version of the ideal result and is
+ null terminated. This is useful for situations where
+ truncation is ok
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function.
+
+--*/
+
+STRSAFEAPI StringCbCopyA(char* pszDest, size_t cbDest, const char* pszSrc);
+STRSAFEAPI StringCbCopyW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc);
+#ifdef UNICODE
+#define StringCbCopy StringCbCopyW
+#else
+#define StringCbCopy StringCbCopyA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbCopyA(char* pszDest, size_t cbDest, const char* pszSrc)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ // convert to count of characters
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyWorkerA(pszDest, cchDest, pszSrc);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCbCopyW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ // convert to count of characters
+ cchDest = cbDest / sizeof(wchar_t);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyWorkerW(pszDest, cchDest, pszSrc);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI
+StringCchCopyEx(
+ OUT LPTSTR pszDest OPTIONAL,
+ IN size_t cchDest,
+ IN LPCTSTR pszSrc OPTIONAL,
+ OUT LPTSTR* ppszDestEnd OPTIONAL,
+ OUT size_t* pcchRemaining OPTIONAL,
+ IN DWORD dwFlags
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strcpy' with
+ some additional parameters. In addition to functionality provided by
+ StringCchCopy, this routine also returns a pointer to the end of the
+ destination string and the number of characters left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string
+
+ cchDest - size of destination buffer in characters.
+ length must be = (_tcslen(pszSrc) + 1) to hold all of
+ the source including the null terminator
+
+ pszSrc - source string which must be null terminated
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function copied any data, the result will point to the
+ null termination character
+
+ pcchRemaining - if pcchRemaining is non-null, the function will return the
+ number of characters left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT("")).
+ this flag is useful for emulating functions like lstrcpy
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any truncated
+ string returned when the failure is
+ STRSAFE_E_INSUFFICIENT_BUFFER
+
+ STRSAFE_NO_TRUNCATION /
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any truncated string
+ returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
+ is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
+ may be NULL. An error may still be returned even though NULLS are ignored
+ due to insufficient space.
+
+Return Value:
+
+ S_OK - if there was source data and it was all copied and the
+ resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the copy
+ operation failed due to insufficient space. When this
+ error occurs, the destination buffer is modified to
+ contain a truncated version of the ideal result and is
+ null terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCchCopyExA(char* pszDest, size_t cchDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCchCopyExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+#ifdef UNICODE
+#define StringCchCopyEx StringCchCopyExW
+#else
+#define StringCchCopyEx StringCchCopyExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchCopyExA(char* pszDest, size_t cchDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
+ cbDest = cchDest * sizeof(char);
+
+ hr = StringCopyExWorkerA(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCchCopyExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
+ cbDest = cchDest * sizeof(wchar_t);
+
+ hr = StringCopyExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI
+StringCbCopyEx(
+ OUT LPTSTR pszDest OPTIONAL,
+ IN size_t cbDest,
+ IN LPCTSTR pszSrc OPTIONAL,
+ OUT LPTSTR* ppszDestEnd OPTIONAL,
+ OUT size_t* pcbRemaining OPTIONAL,
+ IN DWORD dwFlags
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strcpy' with
+ some additional parameters. In addition to functionality provided by
+ StringCbCopy, this routine also returns a pointer to the end of the
+ destination string and the number of bytes left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string
+
+ cbDest - size of destination buffer in bytes.
+ length must be ((_tcslen(pszSrc) + 1) * sizeof(TCHAR)) to
+ hold all of the source including the null terminator
+
+ pszSrc - source string which must be null terminated
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function copied any data, the result will point to the
+ null termination character
+
+ pcbRemaining - pcbRemaining is non-null,the function will return the
+ number of bytes left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT("")).
+ this flag is useful for emulating functions like lstrcpy
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any truncated
+ string returned when the failure is
+ STRSAFE_E_INSUFFICIENT_BUFFER
+
+ STRSAFE_NO_TRUNCATION /
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any truncated string
+ returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
+ is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
+ may be NULL. An error may still be returned even though NULLS are ignored
+ due to insufficient space.
+
+Return Value:
+
+ S_OK - if there was source data and it was all copied and the
+ resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the copy
+ operation failed due to insufficient space. When this
+ error occurs, the destination buffer is modified to
+ contain a truncated version of the ideal result and is
+ null terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCbCopyExA(char* pszDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCbCopyExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
+#ifdef UNICODE
+#define StringCbCopyEx StringCbCopyExW
+#else
+#define StringCbCopyEx StringCbCopyExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbCopyExA(char* pszDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyExWorkerA(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
+ *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCbCopyExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(wchar_t);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
+ *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
+ }
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI
+StringCchCopyN(
+ OUT LPTSTR pszDest,
+ IN size_t cchDest,
+ IN LPCTSTR pszSrc,
+ IN size_t cchSrc
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strncpy'.
+ The size of the destination buffer (in characters) is a parameter and
+ this function will not write past the end of this buffer and it will
+ ALWAYS null terminate the destination buffer (unless it is zero length).
+
+ This routine is meant as a replacement for strncpy, but it does behave
+ differently. This function will not pad the destination buffer with extra
+ null termination characters if cchSrc is greater than the length of pszSrc.
+
+ This function returns a hresult, and not a pointer. It returns
+ S_OK if the entire string or the first cchSrc characters were copied
+ without truncation and the resultant destination string was null terminated,
+ otherwise it will return a failure code. In failure cases as much of pszSrc
+ will be copied to pszDest as possible, and pszDest will be null terminated.
+
+Arguments:
+
+ pszDest - destination string
+
+ cchDest - size of destination buffer in characters.
+ length must be = (_tcslen(src) + 1) to hold all of the
+ source including the null terminator
+
+ pszSrc - source string
+
+ cchSrc - maximum number of characters to copy from source string,
+ not including the null terminator.
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL. See StringCchCopyNEx if you require
+ the handling of NULL values.
+
+Return Value:
+
+ S_OK - if there was source data and it was all copied and the
+ resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the copy
+ operation failed due to insufficient space. When this
+ error occurs, the destination buffer is modified to
+ contain a truncated version of the ideal result and is
+ null terminated. This is useful for situations where
+ truncation is ok
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function.
+
+--*/
+
+STRSAFEAPI StringCchCopyNA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc);
+STRSAFEAPI StringCchCopyNW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc);
+#ifdef UNICODE
+#define StringCchCopyN StringCchCopyNW
+#else
+#define StringCchCopyN StringCchCopyNA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchCopyNA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc)
+{
+ HRESULT hr;
+
+ if ((cchDest > STRSAFE_MAX_CCH) ||
+ (cchSrc > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyNWorkerA(pszDest, cchDest, pszSrc, cchSrc);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCchCopyNW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc)
+{
+ HRESULT hr;
+
+ if ((cchDest > STRSAFE_MAX_CCH) ||
+ (cchSrc > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyNWorkerW(pszDest, cchDest, pszSrc, cchSrc);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI
+StringCbCopyN(
+ OUT LPTSTR pszDest,
+ IN size_t cbDest,
+ IN LPCTSTR pszSrc,
+ IN size_t cbSrc
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strncpy'.
+ The size of the destination buffer (in bytes) is a parameter and this
+ function will not write past the end of this buffer and it will ALWAYS
+ null terminate the destination buffer (unless it is zero length).
+
+ This routine is meant as a replacement for strncpy, but it does behave
+ differently. This function will not pad the destination buffer with extra
+ null termination characters if cbSrc is greater than the size of pszSrc.
+
+ This function returns a hresult, and not a pointer. It returns
+ S_OK if the entire string or the first cbSrc characters were
+ copied without truncation and the resultant destination string was null
+ terminated, otherwise it will return a failure code. In failure cases as
+ much of pszSrc will be copied to pszDest as possible, and pszDest will be
+ null terminated.
+
+Arguments:
+
+ pszDest - destination string
+
+ cbDest - size of destination buffer in bytes.
+ length must be = ((_tcslen(src) + 1) * sizeof(TCHAR)) to
+ hold all of the source including the null terminator
+
+ pszSrc - source string
+
+ cbSrc - maximum number of bytes to copy from source string,
+ not including the null terminator.
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL. See StringCbCopyEx if you require
+ the handling of NULL values.
+
+Return Value:
+
+ S_OK - if there was source data and it was all copied and the
+ resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the copy
+ operation failed due to insufficient space. When this
+ error occurs, the destination buffer is modified to
+ contain a truncated version of the ideal result and is
+ null terminated. This is useful for situations where
+ truncation is ok
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function.
+
+--*/
+
+STRSAFEAPI StringCbCopyNA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbSrc);
+STRSAFEAPI StringCbCopyNW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbSrc);
+#ifdef UNICODE
+#define StringCbCopyN StringCbCopyNW
+#else
+#define StringCbCopyN StringCbCopyNA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbCopyNA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbSrc)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchSrc;
+
+ // convert to count of characters
+ cchDest = cbDest / sizeof(char);
+ cchSrc = cbSrc / sizeof(char);
+
+ if ((cchDest > STRSAFE_MAX_CCH) ||
+ (cchSrc > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyNWorkerA(pszDest, cchDest, pszSrc, cchSrc);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCbCopyNW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbSrc)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchSrc;
+
+ // convert to count of characters
+ cchDest = cbDest / sizeof(wchar_t);
+ cchSrc = cbSrc / sizeof(wchar_t);
+
+ if ((cchDest > STRSAFE_MAX_CCH) ||
+ (cchSrc > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyNWorkerW(pszDest, cchDest, pszSrc, cchSrc);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI
+StringCchCopyNEx(
+ OUT LPTSTR pszDest OPTIONAL,
+ IN size_t cchDest,
+ IN LPCTSTR pszSrc OPTIONAL,
+ IN size_t cchSrc,
+ OUT LPTSTR* ppszDestEnd OPTIONAL,
+ OUT size_t* pcchRemaining OPTIONAL,
+ IN DWORD dwFlags
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strncpy' with
+ some additional parameters. In addition to functionality provided by
+ StringCchCopyN, this routine also returns a pointer to the end of the
+ destination string and the number of characters left in the destination
+ string including the null terminator. The flags parameter allows
+ additional controls.
+
+ This routine is meant as a replacement for strncpy, but it does behave
+ differently. This function will not pad the destination buffer with extra
+ null termination characters if cchSrc is greater than the length of pszSrc.
+
+Arguments:
+
+ pszDest - destination string
+
+ cchDest - size of destination buffer in characters.
+ length must be = (_tcslen(pszSrc) + 1) to hold all of
+ the source including the null terminator
+
+ pszSrc - source string
+
+ cchSrc - maximum number of characters to copy from the source
+ string
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function copied any data, the result will point to the
+ null termination character
+
+ pcchRemaining - if pcchRemaining is non-null, the function will return the
+ number of characters left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT("")).
+ this flag is useful for emulating functions like lstrcpy
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any truncated
+ string returned when the failure is
+ STRSAFE_E_INSUFFICIENT_BUFFER
+
+ STRSAFE_NO_TRUNCATION /
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any truncated string
+ returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
+ is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
+ may be NULL. An error may still be returned even though NULLS are ignored
+ due to insufficient space.
+
+Return Value:
+
+ S_OK - if there was source data and it was all copied and the
+ resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the copy
+ operation failed due to insufficient space. When this
+ error occurs, the destination buffer is modified to
+ contain a truncated version of the ideal result and is
+ null terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCchCopyNExA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCchCopyNExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+#ifdef UNICODE
+#define StringCchCopyNEx StringCchCopyNExW
+#else
+#define StringCchCopyNEx StringCchCopyNExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchCopyNExA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+
+ if ((cchDest > STRSAFE_MAX_CCH) ||
+ (cchSrc > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
+ cbDest = cchDest * sizeof(char);
+
+ hr = StringCopyNExWorkerA(pszDest, cchDest, cbDest, pszSrc, cchSrc, ppszDestEnd, pcchRemaining, dwFlags);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCchCopyNExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+
+ if ((cchDest > STRSAFE_MAX_CCH) ||
+ (cchSrc > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
+ cbDest = cchDest * sizeof(wchar_t);
+
+ hr = StringCopyNExWorkerW(pszDest, cchDest, cbDest, pszSrc, cchSrc, ppszDestEnd, pcchRemaining, dwFlags);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI
+StringCbCopyNEx(
+ OUT LPTSTR pszDest OPTIONAL,
+ IN size_t cbDest,
+ IN LPCTSTR pszSrc OPTIONAL,
+ IN size_t cbSrc,
+ OUT LPTSTR* ppszDestEnd OPTIONAL,
+ OUT size_t* pcbRemaining OPTIONAL,
+ IN DWORD dwFlags
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strncpy' with
+ some additional parameters. In addition to functionality provided by
+ StringCbCopyN, this routine also returns a pointer to the end of the
+ destination string and the number of bytes left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+ This routine is meant as a replacement for strncpy, but it does behave
+ differently. This function will not pad the destination buffer with extra
+ null termination characters if cbSrc is greater than the size of pszSrc.
+
+Arguments:
+
+ pszDest - destination string
+
+ cbDest - size of destination buffer in bytes.
+ length must be ((_tcslen(pszSrc) + 1) * sizeof(TCHAR)) to
+ hold all of the source including the null terminator
+
+ pszSrc - source string
+
+ cbSrc - maximum number of bytes to copy from source string
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function copied any data, the result will point to the
+ null termination character
+
+ pcbRemaining - pcbRemaining is non-null,the function will return the
+ number of bytes left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT("")).
+ this flag is useful for emulating functions like lstrcpy
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any truncated
+ string returned when the failure is
+ STRSAFE_E_INSUFFICIENT_BUFFER
+
+ STRSAFE_NO_TRUNCATION /
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any truncated string
+ returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
+ is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
+ may be NULL. An error may still be returned even though NULLS are ignored
+ due to insufficient space.
+
+Return Value:
+
+ S_OK - if there was source data and it was all copied and the
+ resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the copy
+ operation failed due to insufficient space. When this
+ error occurs, the destination buffer is modified to
+ contain a truncated version of the ideal result and is
+ null terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCbCopyNExA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCbCopyNExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
+#ifdef UNICODE
+#define StringCbCopyNEx StringCbCopyNExW
+#else
+#define StringCbCopyNEx StringCbCopyNExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbCopyNExA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchSrc;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(char);
+ cchSrc = cbSrc / sizeof(char);
+
+ if ((cchDest > STRSAFE_MAX_CCH) ||
+ (cchSrc > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyNExWorkerA(pszDest, cchDest, cbDest, pszSrc, cchSrc, ppszDestEnd, &cchRemaining, dwFlags);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
+ *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCbCopyNExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchSrc;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(wchar_t);
+ cchSrc = cbSrc / sizeof(wchar_t);
+
+ if ((cchDest > STRSAFE_MAX_CCH) ||
+ (cchSrc > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyNExWorkerW(pszDest, cchDest, cbDest, pszSrc, cchSrc, ppszDestEnd, &cchRemaining, dwFlags);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
+ *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
+ }
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI
+StringCchCat(
+ IN OUT LPTSTR pszDest,
+ IN size_t cchDest,
+ IN LPCTSTR pszSrc
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strcat'.
+ The size of the destination buffer (in characters) is a parameter and this
+ function will not write past the end of this buffer and it will ALWAYS
+ null terminate the destination buffer (unless it is zero length).
+
+ This function returns a hresult, and not a pointer. It returns
+ S_OK if the string was concatenated without truncation and null terminated,
+ otherwise it will return a failure code. In failure cases as much of pszSrc
+ will be appended to pszDest as possible, and pszDest will be null
+ terminated.
+
+Arguments:
+
+ pszDest - destination string which must be null terminated
+
+ cchDest - size of destination buffer in characters.
+ length must be = (_tcslen(pszDest) + _tcslen(pszSrc) + 1)
+ to hold all of the combine string plus the null
+ terminator
+
+ pszSrc - source string which must be null terminated
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL. See StringCchCatEx if you require
+ the handling of NULL values.
+
+Return Value:
+
+ S_OK - if there was source data and it was all concatenated and
+ the resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the operation
+ failed due to insufficient space. When this error occurs,
+ the destination buffer is modified to contain a truncated
+ version of the ideal result and is null terminated. This
+ is useful for situations where truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCchCatA(char* pszDest, size_t cchDest, const char* pszSrc);
+STRSAFEAPI StringCchCatW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc);
+#ifdef UNICODE
+#define StringCchCat StringCchCatW
+#else
+#define StringCchCat StringCchCatA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchCatA(char* pszDest, size_t cchDest, const char* pszSrc)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCatWorkerA(pszDest, cchDest, pszSrc);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCchCatW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCatWorkerW(pszDest, cchDest, pszSrc);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI
+StringCbCat(
+ IN OUT LPTSTR pszDest,
+ IN size_t cbDest,
+ IN LPCTSTR pszSrc
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strcat'.
+ The size of the destination buffer (in bytes) is a parameter and this
+ function will not write past the end of this buffer and it will ALWAYS
+ null terminate the destination buffer (unless it is zero length).
+
+ This function returns a hresult, and not a pointer. It returns
+ S_OK if the string was concatenated without truncation and null terminated,
+ otherwise it will return a failure code. In failure cases as much of pszSrc
+ will be appended to pszDest as possible, and pszDest will be null
+ terminated.
+
+Arguments:
+
+ pszDest - destination string which must be null terminated
+
+ cbDest - size of destination buffer in bytes.
+ length must be = ((_tcslen(pszDest) + _tcslen(pszSrc) + 1) * sizeof(TCHAR)
+ to hold all of the combine string plus the null
+ terminator
+
+ pszSrc - source string which must be null terminated
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL. See StringCbCatEx if you require
+ the handling of NULL values.
+
+Return Value:
+
+ S_OK - if there was source data and it was all concatenated and
+ the resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the operation
+ failed due to insufficient space. When this error occurs,
+ the destination buffer is modified to contain a truncated
+ version of the ideal result and is null terminated. This
+ is useful for situations where truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCbCatA(char* pszDest, size_t cbDest, const char* pszSrc);
+STRSAFEAPI StringCbCatW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc);
+#ifdef UNICODE
+#define StringCbCat StringCbCatW
+#else
+#define StringCbCat StringCbCatA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbCatA(char* pszDest, size_t cbDest, const char* pszSrc)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCatWorkerA(pszDest, cchDest, pszSrc);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCbCatW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ cchDest = cbDest / sizeof(wchar_t);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCatWorkerW(pszDest, cchDest, pszSrc);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI
+StringCchCatEx(
+ IN OUT LPTSTR pszDest OPTIONAL,
+ IN size_t cchDest,
+ IN LPCTSTR pszSrc OPTIONAL,
+ OUT LPTSTR* ppszDestEnd OPTIONAL,
+ OUT size_t* pcchRemaining OPTIONAL,
+ IN DWORD dwFlags
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strcat' with
+ some additional parameters. In addition to functionality provided by
+ StringCchCat, this routine also returns a pointer to the end of the
+ destination string and the number of characters left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string which must be null terminated
+
+ cchDest - size of destination buffer in characters
+ length must be (_tcslen(pszDest) + _tcslen(pszSrc) + 1)
+ to hold all of the combine string plus the null
+ terminator.
+
+ pszSrc - source string which must be null terminated
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function appended any data, the result will point to the
+ null termination character
+
+ pcchRemaining - if pcchRemaining is non-null, the function will return the
+ number of characters left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT("")).
+ this flag is useful for emulating functions like lstrcat
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any pre-existing
+ or truncated string
+
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any pre-existing or
+ truncated string
+
+ STRSAFE_NO_TRUNCATION
+ if the function returns STRSAFE_E_INSUFFICIENT_BUFFER, pszDest
+ will not contain a truncated string, it will remain unchanged.
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
+ is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
+ may be NULL. An error may still be returned even though NULLS are ignored
+ due to insufficient space.
+
+Return Value:
+
+ S_OK - if there was source data and it was all concatenated and
+ the resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the operation
+ failed due to insufficient space. When this error
+ occurs, the destination buffer is modified to contain
+ a truncated version of the ideal result and is null
+ terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCchCatExA(char* pszDest, size_t cchDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCchCatExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+#ifdef UNICODE
+#define StringCchCatEx StringCchCatExW
+#else
+#define StringCchCatEx StringCchCatExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchCatExA(char* pszDest, size_t cchDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
+ cbDest = cchDest * sizeof(char);
+
+ hr = StringCatExWorkerA(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCchCatExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
+ cbDest = cchDest * sizeof(wchar_t);
+
+ hr = StringCatExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI
+StringCbCatEx(
+ IN OUT LPTSTR pszDest OPTIONAL,
+ IN size_t cbDest,
+ IN LPCTSTR pszSrc OPTIONAL,
+ OUT LPTSTR* ppszDestEnd OPTIONAL,
+ OUT size_t* pcbRemaining OPTIONAL,
+ IN DWORD dwFlags
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strcat' with
+ some additional parameters. In addition to functionality provided by
+ StringCbCat, this routine also returns a pointer to the end of the
+ destination string and the number of bytes left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string which must be null terminated
+
+ cbDest - size of destination buffer in bytes.
+ length must be ((_tcslen(pszDest) + _tcslen(pszSrc) + 1) * sizeof(TCHAR)
+ to hold all of the combine string plus the null
+ terminator.
+
+ pszSrc - source string which must be null terminated
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function appended any data, the result will point to the
+ null termination character
+
+ pcbRemaining - if pcbRemaining is non-null, the function will return
+ the number of bytes left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT("")).
+ this flag is useful for emulating functions like lstrcat
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any pre-existing
+ or truncated string
+
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any pre-existing or
+ truncated string
+
+ STRSAFE_NO_TRUNCATION
+ if the function returns STRSAFE_E_INSUFFICIENT_BUFFER, pszDest
+ will not contain a truncated string, it will remain unchanged.
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
+ is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
+ may be NULL. An error may still be returned even though NULLS are ignored
+ due to insufficient space.
+
+Return Value:
+
+ S_OK - if there was source data and it was all concatenated
+ and the resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the operation
+ failed due to insufficient space. When this error
+ occurs, the destination buffer is modified to contain
+ a truncated version of the ideal result and is null
+ terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCbCatExA(char* pszDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCbCatExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
+#ifdef UNICODE
+#define StringCbCatEx StringCbCatExW
+#else
+#define StringCbCatEx StringCbCatExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbCatExA(char* pszDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCatExWorkerA(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
+ *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCbCatExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(wchar_t);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCatExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
+ *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
+ }
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI
+StringCchCatN(
+ IN OUT LPTSTR pszDest,
+ IN size_t cchDest,
+ IN LPCTSTR pszSrc,
+ IN size_t cchMaxAppend
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strncat'.
+ The size of the destination buffer (in characters) is a parameter as well as
+ the maximum number of characters to append, excluding the null terminator.
+ This function will not write past the end of the destination buffer and it will
+ ALWAYS null terminate pszDest (unless it is zero length).
+
+ This function returns a hresult, and not a pointer. It returns
+ S_OK if all of pszSrc or the first cchMaxAppend characters were appended
+ to the destination string and it was null terminated, otherwise it will
+ return a failure code. In failure cases as much of pszSrc will be appended
+ to pszDest as possible, and pszDest will be null terminated.
+
+Arguments:
+
+ pszDest - destination string which must be null terminated
+
+ cchDest - size of destination buffer in characters.
+ length must be (_tcslen(pszDest) + min(cchMaxAppend, _tcslen(pszSrc)) + 1)
+ to hold all of the combine string plus the null
+ terminator.
+
+ pszSrc - source string
+
+ cchMaxAppend - maximum number of characters to append
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL. See StringCchCatNEx if you require
+ the handling of NULL values.
+
+Return Value:
+
+ S_OK - if all of pszSrc or the first cchMaxAppend characters
+ were concatenated to pszDest and the resultant dest
+ string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the operation
+ failed due to insufficient space. When this error
+ occurs, the destination buffer is modified to contain
+ a truncated version of the ideal result and is null
+ terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCchCatNA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend);
+STRSAFEAPI StringCchCatNW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend);
+#ifdef UNICODE
+#define StringCchCatN StringCchCatNW
+#else
+#define StringCchCatN StringCchCatNA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchCatNA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCatNWorkerA(pszDest, cchDest, pszSrc, cchMaxAppend);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCchCatNW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCatNWorkerW(pszDest, cchDest, pszSrc, cchMaxAppend);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI
+StringCbCatN(
+ IN OUT LPTSTR pszDest,
+ IN size_t cbDest,
+ IN LPCTSTR pszSrc,
+ IN size_t cbMaxAppend
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strncat'.
+ The size of the destination buffer (in bytes) is a parameter as well as
+ the maximum number of bytes to append, excluding the null terminator.
+ This function will not write past the end of the destination buffer and it will
+ ALWAYS null terminate pszDest (unless it is zero length).
+
+ This function returns a hresult, and not a pointer. It returns
+ S_OK if all of pszSrc or the first cbMaxAppend bytes were appended
+ to the destination string and it was null terminated, otherwise it will
+ return a failure code. In failure cases as much of pszSrc will be appended
+ to pszDest as possible, and pszDest will be null terminated.
+
+Arguments:
+
+ pszDest - destination string which must be null terminated
+
+ cbDest - size of destination buffer in bytes.
+ length must be ((_tcslen(pszDest) + min(cbMaxAppend / sizeof(TCHAR), _tcslen(pszSrc)) + 1) * sizeof(TCHAR)
+ to hold all of the combine string plus the null
+ terminator.
+
+ pszSrc - source string
+
+ cbMaxAppend - maximum number of bytes to append
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL. See StringCbCatNEx if you require
+ the handling of NULL values.
+
+Return Value:
+
+ S_OK - if all of pszSrc or the first cbMaxAppend bytes were
+ concatenated to pszDest and the resultant dest string
+ was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the operation
+ failed due to insufficient space. When this error
+ occurs, the destination buffer is modified to contain
+ a truncated version of the ideal result and is null
+ terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCbCatNA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbMaxAppend);
+STRSAFEAPI StringCbCatNW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbMaxAppend);
+#ifdef UNICODE
+#define StringCbCatN StringCbCatNW
+#else
+#define StringCbCatN StringCbCatNA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbCatNA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbMaxAppend)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cchMaxAppend;
+
+ cchMaxAppend = cbMaxAppend / sizeof(char);
+
+ hr = StringCatNWorkerA(pszDest, cchDest, pszSrc, cchMaxAppend);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCbCatNW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbMaxAppend)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ cchDest = cbDest / sizeof(wchar_t);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cchMaxAppend;
+
+ cchMaxAppend = cbMaxAppend / sizeof(wchar_t);
+
+ hr = StringCatNWorkerW(pszDest, cchDest, pszSrc, cchMaxAppend);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI
+StringCchCatNEx(
+ IN OUT LPTSTR pszDest OPTIONAL,
+ IN size_t cchDest,
+ IN LPCTSTR pszSrc OPTIONAL,
+ IN size_t cchMaxAppend,
+ OUT LPTSTR* ppszDestEnd OPTIONAL,
+ OUT size_t* pcchRemaining OPTIONAL,
+ IN DWORD dwFlags
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strncat', with
+ some additional parameters. In addition to functionality provided by
+ StringCchCatN, this routine also returns a pointer to the end of the
+ destination string and the number of characters left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string which must be null terminated
+
+ cchDest - size of destination buffer in characters.
+ length must be (_tcslen(pszDest) + min(cchMaxAppend, _tcslen(pszSrc)) + 1)
+ to hold all of the combine string plus the null
+ terminator.
+
+ pszSrc - source string
+
+ cchMaxAppend - maximum number of characters to append
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function appended any data, the result will point to the
+ null termination character
+
+ pcchRemaining - if pcchRemaining is non-null, the function will return the
+ number of characters left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT(""))
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any pre-existing
+ or truncated string
+
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any pre-existing or
+ truncated string
+
+ STRSAFE_NO_TRUNCATION
+ if the function returns STRSAFE_E_INSUFFICIENT_BUFFER, pszDest
+ will not contain a truncated string, it will remain unchanged.
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
+ is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
+ may be NULL. An error may still be returned even though NULLS are ignored
+ due to insufficient space.
+
+Return Value:
+
+ S_OK - if all of pszSrc or the first cchMaxAppend characters
+ were concatenated to pszDest and the resultant dest
+ string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the operation
+ failed due to insufficient space. When this error
+ occurs, the destination buffer is modified to contain
+ a truncated version of the ideal result and is null
+ terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCchCatNExA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCchCatNExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+#ifdef UNICODE
+#define StringCchCatNEx StringCchCatNExW
+#else
+#define StringCchCatNEx StringCchCatNExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchCatNExA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
+ cbDest = cchDest * sizeof(char);
+
+ hr = StringCatNExWorkerA(pszDest, cchDest, cbDest, pszSrc, cchMaxAppend, ppszDestEnd, pcchRemaining, dwFlags);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCchCatNExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
+ cbDest = cchDest * sizeof(wchar_t);
+
+ hr = StringCatNExWorkerW(pszDest, cchDest, cbDest, pszSrc, cchMaxAppend, ppszDestEnd, pcchRemaining, dwFlags);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI
+StringCbCatNEx(
+ IN OUT LPTSTR pszDest OPTIONAL,
+ IN size_t cbDest,
+ IN LPCTSTR pszSrc OPTIONAL,
+ IN size_t cbMaxAppend,
+ OUT LPTSTR* ppszDestEnd OPTIONAL,
+ OUT size_t* pcchRemaining OPTIONAL,
+ IN DWORD dwFlags
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strncat', with
+ some additional parameters. In addition to functionality provided by
+ StringCbCatN, this routine also returns a pointer to the end of the
+ destination string and the number of bytes left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string which must be null terminated
+
+ cbDest - size of destination buffer in bytes.
+ length must be ((_tcslen(pszDest) + min(cbMaxAppend / sizeof(TCHAR), _tcslen(pszSrc)) + 1) * sizeof(TCHAR)
+ to hold all of the combine string plus the null
+ terminator.
+
+ pszSrc - source string
+
+ cbMaxAppend - maximum number of bytes to append
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function appended any data, the result will point to the
+ null termination character
+
+ pcbRemaining - if pcbRemaining is non-null, the function will return the
+ number of bytes left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT(""))
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any pre-existing
+ or truncated string
+
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any pre-existing or
+ truncated string
+
+ STRSAFE_NO_TRUNCATION
+ if the function returns STRSAFE_E_INSUFFICIENT_BUFFER, pszDest
+ will not contain a truncated string, it will remain unchanged.
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
+ is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
+ may be NULL. An error may still be returned even though NULLS are ignored
+ due to insufficient space.
+
+Return Value:
+
+ S_OK - if all of pszSrc or the first cbMaxAppend bytes were
+ concatenated to pszDest and the resultant dest string
+ was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the operation
+ failed due to insufficient space. When this error
+ occurs, the destination buffer is modified to contain
+ a truncated version of the ideal result and is null
+ terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCbCatNExA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbMaxAppend, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCbCatNExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbMaxAppend, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
+#ifdef UNICODE
+#define StringCbCatNEx StringCbCatNExW
+#else
+#define StringCbCatNEx StringCbCatNExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbCatNExA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbMaxAppend, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cchMaxAppend;
+
+ cchMaxAppend = cbMaxAppend / sizeof(char);
+
+ hr = StringCatNExWorkerA(pszDest, cchDest, cbDest, pszSrc, cchMaxAppend, ppszDestEnd, &cchRemaining, dwFlags);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
+ *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCbCatNExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbMaxAppend, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(wchar_t);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cchMaxAppend;
+
+ cchMaxAppend = cbMaxAppend / sizeof(wchar_t);
+
+ hr = StringCatNExWorkerW(pszDest, cchDest, cbDest, pszSrc, cchMaxAppend, ppszDestEnd, &cchRemaining, dwFlags);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
+ *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
+ }
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI
+StringCchVPrintf(
+ OUT LPTSTR pszDest,
+ IN size_t cchDest,
+ IN LPCTSTR pszFormat,
+ IN va_list argList
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'vsprintf'.
+ The size of the destination buffer (in characters) is a parameter and
+ this function will not write past the end of this buffer and it will
+ ALWAYS null terminate the destination buffer (unless it is zero length).
+
+ This function returns a hresult, and not a pointer. It returns
+ S_OK if the string was printed without truncation and null terminated,
+ otherwise it will return a failure code. In failure cases it will return
+ a truncated version of the ideal result.
+
+Arguments:
+
+ pszDest - destination string
+
+ cchDest - size of destination buffer in characters
+ length must be sufficient to hold the resulting formatted
+ string, including the null terminator.
+
+ pszFormat - format string which must be null terminated
+
+ argList - va_list from the variable arguments according to the
+ stdarg.h convention
+
+Notes:
+ Behavior is undefined if destination, format strings or any arguments
+ strings overlap.
+
+ pszDest and pszFormat should not be NULL. See StringCchVPrintfEx if you
+ require the handling of NULL values.
+
+Return Value:
+
+ S_OK - if there was sufficient space in the dest buffer for
+ the resultant string and it was null terminated.
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the print
+ operation failed due to insufficient space. When this
+ error occurs, the destination buffer is modified to
+ contain a truncated version of the ideal result and is
+ null terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCchVPrintfA(char* pszDest, size_t cchDest, const char* pszFormat, va_list argList);
+STRSAFEAPI StringCchVPrintfW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, va_list argList);
+#ifdef UNICODE
+#define StringCchVPrintf StringCchVPrintfW
+#else
+#define StringCchVPrintf StringCchVPrintfA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchVPrintfA(char* pszDest, size_t cchDest, const char* pszFormat, va_list argList)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringVPrintfWorkerA(pszDest, cchDest, pszFormat, argList);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCchVPrintfW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, va_list argList)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI
+StringCbVPrintf(
+ OUT LPTSTR pszDest,
+ IN size_t cbDest,
+ IN LPCTSTR pszFormat,
+ IN va_list argList
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'vsprintf'.
+ The size of the destination buffer (in bytes) is a parameter and
+ this function will not write past the end of this buffer and it will
+ ALWAYS null terminate the destination buffer (unless it is zero length).
+
+ This function returns a hresult, and not a pointer. It returns
+ S_OK if the string was printed without truncation and null terminated,
+ otherwise it will return a failure code. In failure cases it will return
+ a truncated version of the ideal result.
+
+Arguments:
+
+ pszDest - destination string
+
+ cbDest - size of destination buffer in bytes
+ length must be sufficient to hold the resulting formatted
+ string, including the null terminator.
+
+ pszFormat - format string which must be null terminated
+
+ argList - va_list from the variable arguments according to the
+ stdarg.h convention
+
+Notes:
+ Behavior is undefined if destination, format strings or any arguments
+ strings overlap.
+
+ pszDest and pszFormat should not be NULL. See StringCbVPrintfEx if you
+ require the handling of NULL values.
+
+
+Return Value:
+
+ S_OK - if there was sufficient space in the dest buffer for
+ the resultant string and it was null terminated.
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the print
+ operation failed due to insufficient space. When this
+ error occurs, the destination buffer is modified to
+ contain a truncated version of the ideal result and is
+ null terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCbVPrintfA(char* pszDest, size_t cbDest, const char* pszFormat, va_list argList);
+STRSAFEAPI StringCbVPrintfW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszFormat, va_list argList);
+#ifdef UNICODE
+#define StringCbVPrintf StringCbVPrintfW
+#else
+#define StringCbVPrintf StringCbVPrintfA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbVPrintfA(char* pszDest, size_t cbDest, const char* pszFormat, va_list argList)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringVPrintfWorkerA(pszDest, cchDest, pszFormat, argList);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCbVPrintfW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszFormat, va_list argList)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ cchDest = cbDest / sizeof(wchar_t);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI
+StringCchPrintf(
+ OUT LPTSTR pszDest,
+ IN size_t cchDest,
+ IN LPCTSTR pszFormat,
+ ...
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'sprintf'.
+ The size of the destination buffer (in characters) is a parameter and
+ this function will not write past the end of this buffer and it will
+ ALWAYS null terminate the destination buffer (unless it is zero length).
+
+ This function returns a hresult, and not a pointer. It returns
+ S_OK if the string was printed without truncation and null terminated,
+ otherwise it will return a failure code. In failure cases it will return
+ a truncated version of the ideal result.
+
+Arguments:
+
+ pszDest - destination string
+
+ cchDest - size of destination buffer in characters
+ length must be sufficient to hold the resulting formatted
+ string, including the null terminator.
+
+ pszFormat - format string which must be null terminated
+
+ ... - additional parameters to be formatted according to
+ the format string
+
+Notes:
+ Behavior is undefined if destination, format strings or any arguments
+ strings overlap.
+
+ pszDest and pszFormat should not be NULL. See StringCchPrintfEx if you
+ require the handling of NULL values.
+
+Return Value:
+
+ S_OK - if there was sufficient space in the dest buffer for
+ the resultant string and it was null terminated.
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the print
+ operation failed due to insufficient space. When this
+ error occurs, the destination buffer is modified to
+ contain a truncated version of the ideal result and is
+ null terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCchPrintfA(char* pszDest, size_t cchDest, const char* pszFormat, ...);
+STRSAFEAPI StringCchPrintfW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, ...);
+#ifdef UNICODE
+#define StringCchPrintf StringCchPrintfW
+#else
+#define StringCchPrintf StringCchPrintfA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchPrintfA(char* pszDest, size_t cchDest, const char* pszFormat, ...)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ va_list argList;
+
+ va_start(argList, pszFormat);
+
+ hr = StringVPrintfWorkerA(pszDest, cchDest, pszFormat, argList);
+
+ va_end(argList);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCchPrintfW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, ...)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ va_list argList;
+
+ va_start(argList, pszFormat);
+
+ hr = StringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList);
+
+ va_end(argList);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI
+StringCbPrintf(
+ OUT LPTSTR pszDest,
+ IN size_t cbDest,
+ IN LPCTSTR pszFormat,
+ ...
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'sprintf'.
+ The size of the destination buffer (in bytes) is a parameter and
+ this function will not write past the end of this buffer and it will
+ ALWAYS null terminate the destination buffer (unless it is zero length).
+
+ This function returns a hresult, and not a pointer. It returns
+ S_OK if the string was printed without truncation and null terminated,
+ otherwise it will return a failure code. In failure cases it will return
+ a truncated version of the ideal result.
+
+Arguments:
+
+ pszDest - destination string
+
+ cbDest - size of destination buffer in bytes
+ length must be sufficient to hold the resulting formatted
+ string, including the null terminator.
+
+ pszFormat - format string which must be null terminated
+
+ ... - additional parameters to be formatted according to
+ the format string
+
+Notes:
+ Behavior is undefined if destination, format strings or any arguments
+ strings overlap.
+
+ pszDest and pszFormat should not be NULL. See StringCbPrintfEx if you
+ require the handling of NULL values.
+
+
+Return Value:
+
+ S_OK - if there was sufficient space in the dest buffer for
+ the resultant string and it was null terminated.
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the print
+ operation failed due to insufficient space. When this
+ error occurs, the destination buffer is modified to
+ contain a truncated version of the ideal result and is
+ null terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCbPrintfA(char* pszDest, size_t cbDest, const char* pszFormat, ...);
+STRSAFEAPI StringCbPrintfW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszFormat, ...);
+#ifdef UNICODE
+#define StringCbPrintf StringCbPrintfW
+#else
+#define StringCbPrintf StringCbPrintfA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbPrintfA(char* pszDest, size_t cbDest, const char* pszFormat, ...)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ va_list argList;
+
+ va_start(argList, pszFormat);
+
+ hr = StringVPrintfWorkerA(pszDest, cchDest, pszFormat, argList);
+
+ va_end(argList);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCbPrintfW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszFormat, ...)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ cchDest = cbDest / sizeof(wchar_t);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ va_list argList;
+
+ va_start(argList, pszFormat);
+
+ hr = StringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList);
+
+ va_end(argList);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI
+StringCchPrintfEx(
+ OUT LPTSTR pszDest OPTIONAL,
+ IN size_t cchDest,
+ OUT LPTSTR* ppszDestEnd OPTIONAL,
+ OUT size_t* pcchRemaining OPTIONAL,
+ IN DWORD dwFlags,
+ IN LPCTSTR pszFormat OPTIONAL,
+ ...
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'sprintf' with
+ some additional parameters. In addition to functionality provided by
+ StringCchPrintf, this routine also returns a pointer to the end of the
+ destination string and the number of characters left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string
+
+ cchDest - size of destination buffer in characters.
+ length must be sufficient to contain the resulting
+ formatted string plus the null terminator.
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function printed any data, the result will point to the
+ null termination character
+
+ pcchRemaining - if pcchRemaining is non-null, the function will return
+ the number of characters left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT(""))
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any truncated
+ string returned when the failure is
+ STRSAFE_E_INSUFFICIENT_BUFFER
+
+ STRSAFE_NO_TRUNCATION /
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any truncated string
+ returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
+
+ pszFormat - format string which must be null terminated
+
+ ... - additional parameters to be formatted according to
+ the format string
+
+Notes:
+ Behavior is undefined if destination, format strings or any arguments
+ strings overlap.
+
+ pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS
+ flag is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and
+ pszFormat may be NULL. An error may still be returned even though NULLS
+ are ignored due to insufficient space.
+
+Return Value:
+
+ S_OK - if there was source data and it was all concatenated and
+ the resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the print
+ operation failed due to insufficient space. When this
+ error occurs, the destination buffer is modified to
+ contain a truncated version of the ideal result and is
+ null terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCchPrintfExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, ...);
+STRSAFEAPI StringCchPrintfExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, ...);
+#ifdef UNICODE
+#define StringCchPrintfEx StringCchPrintfExW
+#else
+#define StringCchPrintfEx StringCchPrintfExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchPrintfExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, ...)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+ va_list argList;
+
+ // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
+ cbDest = cchDest * sizeof(char);
+ va_start(argList, pszFormat);
+
+ hr = StringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList);
+
+ va_end(argList);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCchPrintfExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, ...)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+ va_list argList;
+
+ // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
+ cbDest = cchDest * sizeof(wchar_t);
+ va_start(argList, pszFormat);
+
+ hr = StringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList);
+
+ va_end(argList);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI
+StringCbPrintfEx(
+ OUT LPTSTR pszDest OPTIONAL,
+ IN size_t cbDest,
+ OUT LPTSTR* ppszDestEnd OPTIONAL,
+ OUT size_t* pcbRemaining OPTIONAL,
+ IN DWORD dwFlags,
+ IN LPCTSTR pszFormat OPTIONAL,
+ ...
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'sprintf' with
+ some additional parameters. In addition to functionality provided by
+ StringCbPrintf, this routine also returns a pointer to the end of the
+ destination string and the number of bytes left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string
+
+ cbDest - size of destination buffer in bytes.
+ length must be sufficient to contain the resulting
+ formatted string plus the null terminator.
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function printed any data, the result will point to the
+ null termination character
+
+ pcbRemaining - if pcbRemaining is non-null, the function will return
+ the number of bytes left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT(""))
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any truncated
+ string returned when the failure is
+ STRSAFE_E_INSUFFICIENT_BUFFER
+
+ STRSAFE_NO_TRUNCATION /
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any truncated string
+ returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
+
+ pszFormat - format string which must be null terminated
+
+ ... - additional parameters to be formatted according to
+ the format string
+
+Notes:
+ Behavior is undefined if destination, format strings or any arguments
+ strings overlap.
+
+ pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS
+ flag is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and
+ pszFormat may be NULL. An error may still be returned even though NULLS
+ are ignored due to insufficient space.
+
+Return Value:
+
+ S_OK - if there was source data and it was all concatenated and
+ the resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the print
+ operation failed due to insufficient space. When this
+ error occurs, the destination buffer is modified to
+ contain a truncated version of the ideal result and is
+ null terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCbPrintfExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const char* pszFormat, ...);
+STRSAFEAPI StringCbPrintfExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const wchar_t* pszFormat, ...);
+#ifdef UNICODE
+#define StringCbPrintfEx StringCbPrintfExW
+#else
+#define StringCbPrintfEx StringCbPrintfExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbPrintfExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const char* pszFormat, ...)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ va_list argList;
+
+ va_start(argList, pszFormat);
+
+ hr = StringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList);
+
+ va_end(argList);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
+ *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCbPrintfExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const wchar_t* pszFormat, ...)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(wchar_t);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ va_list argList;
+
+ va_start(argList, pszFormat);
+
+ hr = StringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList);
+
+ va_end(argList);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
+ *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
+ }
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI
+StringCchVPrintfEx(
+ OUT LPTSTR pszDest OPTIONAL,
+ IN size_t cchDest,
+ OUT LPTSTR* ppszDestEnd OPTIONAL,
+ OUT size_t* pcchRemaining OPTIONAL,
+ IN DWORD dwFlags,
+ IN LPCTSTR pszFormat OPTIONAL,
+ IN va_list argList
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'vsprintf' with
+ some additional parameters. In addition to functionality provided by
+ StringCchVPrintf, this routine also returns a pointer to the end of the
+ destination string and the number of characters left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string
+
+ cchDest - size of destination buffer in characters.
+ length must be sufficient to contain the resulting
+ formatted string plus the null terminator.
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function printed any data, the result will point to the
+ null termination character
+
+ pcchRemaining - if pcchRemaining is non-null, the function will return
+ the number of characters left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT(""))
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any truncated
+ string returned when the failure is
+ STRSAFE_E_INSUFFICIENT_BUFFER
+
+ STRSAFE_NO_TRUNCATION /
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any truncated string
+ returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
+
+ pszFormat - format string which must be null terminated
+
+ argList - va_list from the variable arguments according to the
+ stdarg.h convention
+
+Notes:
+ Behavior is undefined if destination, format strings or any arguments
+ strings overlap.
+
+ pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS
+ flag is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and
+ pszFormat may be NULL. An error may still be returned even though NULLS
+ are ignored due to insufficient space.
+
+Return Value:
+
+ S_OK - if there was source data and it was all concatenated and
+ the resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the print
+ operation failed due to insufficient space. When this
+ error occurs, the destination buffer is modified to
+ contain a truncated version of the ideal result and is
+ null terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCchVPrintfExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList);
+STRSAFEAPI StringCchVPrintfExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList);
+#ifdef UNICODE
+#define StringCchVPrintfEx StringCchVPrintfExW
+#else
+#define StringCchVPrintfEx StringCchVPrintfExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchVPrintfExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
+ cbDest = cchDest * sizeof(char);
+
+ hr = StringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCchVPrintfExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
+ cbDest = cchDest * sizeof(wchar_t);
+
+ hr = StringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI
+StringCbVPrintfEx(
+ OUT LPTSTR pszDest OPTIONAL,
+ IN size_t cbDest,
+ OUT LPTSTR* ppszDestEnd OPTIONAL,
+ OUT size_t* pcbRemaining OPTIONAL,
+ IN DWORD dwFlags,
+ IN LPCTSTR pszFormat OPTIONAL,
+ IN va_list argList
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'vsprintf' with
+ some additional parameters. In addition to functionality provided by
+ StringCbVPrintf, this routine also returns a pointer to the end of the
+ destination string and the number of characters left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string
+
+ cbDest - size of destination buffer in bytes.
+ length must be sufficient to contain the resulting
+ formatted string plus the null terminator.
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return
+ a pointer to the end of the destination string. If the
+ function printed any data, the result will point to the
+ null termination character
+
+ pcbRemaining - if pcbRemaining is non-null, the function will return
+ the number of bytes left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT(""))
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any truncated
+ string returned when the failure is
+ STRSAFE_E_INSUFFICIENT_BUFFER
+
+ STRSAFE_NO_TRUNCATION /
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any truncated string
+ returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
+
+ pszFormat - format string which must be null terminated
+
+ argList - va_list from the variable arguments according to the
+ stdarg.h convention
+
+Notes:
+ Behavior is undefined if destination, format strings or any arguments
+ strings overlap.
+
+ pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS
+ flag is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and
+ pszFormat may be NULL. An error may still be returned even though NULLS
+ are ignored due to insufficient space.
+
+Return Value:
+
+ S_OK - if there was source data and it was all concatenated and
+ the resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the print
+ operation failed due to insufficient space. When this
+ error occurs, the destination buffer is modified to
+ contain a truncated version of the ideal result and is
+ null terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCbVPrintfExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList);
+STRSAFEAPI StringCbVPrintfExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList);
+#ifdef UNICODE
+#define StringCbVPrintfEx StringCbVPrintfExW
+#else
+#define StringCbVPrintfEx StringCbVPrintfExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbVPrintfExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
+ *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCbVPrintfExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(wchar_t);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
+ *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
+ }
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI
+StringCchGets(
+ OUT LPTSTR pszDest,
+ IN size_t cchDest
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'gets'.
+ The size of the destination buffer (in characters) is a parameter and
+ this function will not write past the end of this buffer and it will
+ ALWAYS null terminate the destination buffer (unless it is zero length).
+
+ This routine is not a replacement for fgets. That function does not replace
+ newline characters with a null terminator.
+
+ This function returns a hresult, and not a pointer. It returns
+ S_OK if any characters were read from stdin and copied to pszDest and
+ pszDest was null terminated, otherwise it will return a failure code.
+
+Arguments:
+
+ pszDest - destination string
+
+ cchDest - size of destination buffer in characters.
+
+Notes:
+ pszDest should not be NULL. See StringCchGetsEx if you require the handling
+ of NULL values.
+
+ cchDest must be > 1 for this function to succeed.
+
+Return Value:
+
+ S_OK - data was read from stdin and copied, and the resultant
+ dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_END_OF_FILE /
+ HRESULT_CODE(hr) == ERROR_HANDLE_EOF
+ - this return value indicates an error or end-of-file
+ condition, use feof or ferror to determine which one has
+ occured.
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that there was
+ insufficient space in the destination buffer to copy any
+ data
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function.
+
+--*/
+
+#ifndef STRSAFE_LIB_IMPL
+STRSAFE_INLINE_API StringCchGetsA(char* pszDest, size_t cchDest);
+STRSAFE_INLINE_API StringCchGetsW(wchar_t* pszDest, size_t cchDest);
+#ifdef UNICODE
+#define StringCchGets StringCchGetsW
+#else
+#define StringCchGets StringCchGetsA
+#endif // !UNICODE
+
+STRSAFE_INLINE_API StringCchGetsA(char* pszDest, size_t cchDest)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
+ cbDest = cchDest * sizeof(char);
+
+ hr = StringGetsExWorkerA(pszDest, cchDest, cbDest, NULL, NULL, 0);
+ }
+
+ return hr;
+}
+
+STRSAFE_INLINE_API StringCchGetsW(wchar_t* pszDest, size_t cchDest)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
+ cbDest = cchDest * sizeof(wchar_t);
+
+ hr = StringGetsExWorkerW(pszDest, cchDest, cbDest, NULL, NULL, 0);
+ }
+
+ return hr;
+}
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+#endif // !STRSAFE_LIB_IMPL
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI
+StringCbGets(
+ OUT LPTSTR pszDest,
+ IN size_t cbDest
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'gets'.
+ The size of the destination buffer (in bytes) is a parameter and
+ this function will not write past the end of this buffer and it will
+ ALWAYS null terminate the destination buffer (unless it is zero length).
+
+ This routine is not a replacement for fgets. That function does not replace
+ newline characters with a null terminator.
+
+ This function returns a hresult, and not a pointer. It returns
+ S_OK if any characters were read from stdin and copied to pszDest
+ and pszDest was null terminated, otherwise it will return a failure code.
+
+Arguments:
+
+ pszDest - destination string
+
+ cbDest - size of destination buffer in bytes.
+
+Notes:
+ pszDest should not be NULL. See StringCbGetsEx if you require the handling
+ of NULL values.
+
+ cbDest must be > sizeof(TCHAR) for this function to succeed.
+
+Return Value:
+
+ S_OK - data was read from stdin and copied, and the resultant
+ dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_END_OF_FILE /
+ HRESULT_CODE(hr) == ERROR_HANDLE_EOF
+ - this return value indicates an error or end-of-file
+ condition, use feof or ferror to determine which one has
+ occured.
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that there was
+ insufficient space in the destination buffer to copy any
+ data
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function.
+
+--*/
+
+#ifndef STRSAFE_LIB_IMPL
+STRSAFE_INLINE_API StringCbGetsA(char* pszDest, size_t cbDest);
+STRSAFE_INLINE_API StringCbGetsW(wchar_t* pszDest, size_t cbDest);
+#ifdef UNICODE
+#define StringCbGets StringCbGetsW
+#else
+#define StringCbGets StringCbGetsA
+#endif // !UNICODE
+
+STRSAFE_INLINE_API StringCbGetsA(char* pszDest, size_t cbDest)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ // convert to count of characters
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringGetsExWorkerA(pszDest, cchDest, cbDest, NULL, NULL, 0);
+ }
+
+ return hr;
+}
+
+STRSAFE_INLINE_API StringCbGetsW(wchar_t* pszDest, size_t cbDest)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ // convert to count of characters
+ cchDest = cbDest / sizeof(wchar_t);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringGetsExWorkerW(pszDest, cchDest, cbDest, NULL, NULL, 0);
+ }
+
+ return hr;
+}
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+#endif // !STRSAFE_LIB_IMPL
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI
+StringCchGetsEx(
+ OUT LPTSTR pszDest OPTIONAL,
+ IN size_t cchDest,
+ OUT LPTSTR* ppszDestEnd OPTIONAL,
+ OUT size_t* pcchRemaining OPTIONAL,
+ IN DWORD dwFlags
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'gets' with
+ some additional parameters. In addition to functionality provided by
+ StringCchGets, this routine also returns a pointer to the end of the
+ destination string and the number of characters left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string
+
+ cchDest - size of destination buffer in characters.
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function copied any data, the result will point to the
+ null termination character
+
+ pcchRemaining - if pcchRemaining is non-null, the function will return the
+ number of characters left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT("")).
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated.
+
+ STRSAFE_NO_TRUNCATION /
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string.
+
+Notes:
+ pszDest should not be NULL unless the STRSAFE_IGNORE_NULLS flag is specified.
+ If STRSAFE_IGNORE_NULLS is passed and pszDest is NULL, an error may still be
+ returned even though NULLS are ignored
+
+ cchDest must be > 1 for this function to succeed.
+
+Return Value:
+
+ S_OK - data was read from stdin and copied, and the resultant
+ dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_END_OF_FILE /
+ HRESULT_CODE(hr) == ERROR_HANDLE_EOF
+ - this return value indicates an error or end-of-file
+ condition, use feof or ferror to determine which one has
+ occured.
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that there was
+ insufficient space in the destination buffer to copy any
+ data
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function.
+
+--*/
+
+#ifndef STRSAFE_LIB_IMPL
+STRSAFE_INLINE_API StringCchGetsExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFE_INLINE_API StringCchGetsExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+#ifdef UNICODE
+#define StringCchGetsEx StringCchGetsExW
+#else
+#define StringCchGetsEx StringCchGetsExA
+#endif // !UNICODE
+
+STRSAFE_INLINE_API StringCchGetsExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
+ cbDest = cchDest * sizeof(char);
+
+ hr = StringGetsExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags);
+ }
+
+ return hr;
+}
+
+STRSAFE_INLINE_API StringCchGetsExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
+ cbDest = cchDest * sizeof(wchar_t);
+
+ hr = StringGetsExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags);
+ }
+
+ return hr;
+}
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+#endif // !STRSAFE_LIB_IMPL
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI
+StringCbGetsEx(
+ OUT LPTSTR pszDest OPTIONAL,
+ IN size_t cbDest,
+ OUT LPTSTR* ppszDestEnd OPTIONAL,
+ OUT size_t* pcbRemaining OPTIONAL,
+ IN DWORD dwFlags
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'gets' with
+ some additional parameters. In addition to functionality provided by
+ StringCbGets, this routine also returns a pointer to the end of the
+ destination string and the number of characters left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string
+
+ cbDest - size of destination buffer in bytes.
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function copied any data, the result will point to the
+ null termination character
+
+ pcbRemaining - if pbRemaining is non-null, the function will return the
+ number of bytes left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT("")).
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated.
+
+ STRSAFE_NO_TRUNCATION /
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string.
+
+Notes:
+ pszDest should not be NULL unless the STRSAFE_IGNORE_NULLS flag is specified.
+ If STRSAFE_IGNORE_NULLS is passed and pszDest is NULL, an error may still be
+ returned even though NULLS are ignored
+
+ cbDest must be > sizeof(TCHAR) for this function to succeed
+
+Return Value:
+
+ S_OK - data was read from stdin and copied, and the resultant
+ dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_END_OF_FILE /
+ HRESULT_CODE(hr) == ERROR_HANDLE_EOF
+ - this return value indicates an error or end-of-file
+ condition, use feof or ferror to determine which one has
+ occured.
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that there was
+ insufficient space in the destination buffer to copy any
+ data
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function.
+
+--*/
+
+#ifndef STRSAFE_LIB_IMPL
+STRSAFE_INLINE_API StringCbGetsExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pbRemaining, unsigned long dwFlags);
+STRSAFE_INLINE_API StringCbGetsExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
+#ifdef UNICODE
+#define StringCbGetsEx StringCbGetsExW
+#else
+#define StringCbGetsEx StringCbGetsExA
+#endif // !UNICODE
+
+STRSAFE_INLINE_API StringCbGetsExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringGetsExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags);
+ }
+
+ if (SUCCEEDED(hr) ||
+ (hr == STRSAFE_E_INSUFFICIENT_BUFFER) ||
+ (hr == STRSAFE_E_END_OF_FILE))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
+ *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
+ }
+ }
+
+ return hr;
+}
+
+STRSAFE_INLINE_API StringCbGetsExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(wchar_t);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringGetsExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags);
+ }
+
+ if (SUCCEEDED(hr) ||
+ (hr == STRSAFE_E_INSUFFICIENT_BUFFER) ||
+ (hr == STRSAFE_E_END_OF_FILE))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
+ *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
+ }
+ }
+
+ return hr;
+}
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+#endif // !STRSAFE_LIB_IMPL
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI
+StringCchLength(
+ IN LPCTSTR psz,
+ IN size_t cchMax,
+ OUT size_t* pcch OPTIONAL
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strlen'.
+ It is used to make sure a string is not larger than a given length, and
+ it optionally returns the current length in characters not including
+ the null terminator.
+
+ This function returns a hresult, and not a pointer. It returns
+ S_OK if the string is non-null and the length including the null
+ terminator is less than or equal to cchMax characters.
+
+Arguments:
+
+ psz - string to check the length of
+
+ cchMax - maximum number of characters including the null terminator
+ that psz is allowed to contain
+
+ pcch - if the function succeeds and pcch is non-null, the current length
+ in characters of psz excluding the null terminator will be returned.
+ This out parameter is equivalent to the return value of strlen(psz)
+
+Notes:
+ psz can be null but the function will fail
+
+ cchMax should be greater than zero or the function will fail
+
+Return Value:
+
+ S_OK - psz is non-null and the length including the null
+ terminator is less than or equal to cchMax characters
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function.
+
+--*/
+
+STRSAFEAPI StringCchLengthA(const char* psz, size_t cchMax, size_t* pcch);
+STRSAFEAPI StringCchLengthW(const wchar_t* psz, size_t cchMax, size_t* pcch);
+#ifdef UNICODE
+#define StringCchLength StringCchLengthW
+#else
+#define StringCchLength StringCchLengthA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchLengthA(const char* psz, size_t cchMax, size_t* pcch)
+{
+ HRESULT hr;
+
+ if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringLengthWorkerA(psz, cchMax, pcch);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCchLengthW(const wchar_t* psz, size_t cchMax, size_t* pcch)
+{
+ HRESULT hr;
+
+ if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringLengthWorkerW(psz, cchMax, pcch);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI
+StringCbLength(
+ IN LPCTSTR psz,
+ IN size_t cbMax,
+ OUT size_t* pcb OPTIONAL
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strlen'.
+ It is used to make sure a string is not larger than a given length, and
+ it optionally returns the current length in bytes not including
+ the null terminator.
+
+ This function returns a hresult, and not a pointer. It returns
+ S_OK if the string is non-null and the length including the null
+ terminator is less than or equal to cbMax bytes.
+
+Arguments:
+
+ psz - string to check the length of
+
+ cbMax - maximum number of bytes including the null terminator
+ that psz is allowed to contain
+
+ pcb - if the function succeeds and pcb is non-null, the current length
+ in bytes of psz excluding the null terminator will be returned.
+ This out parameter is equivalent to the return value of strlen(psz) * sizeof(TCHAR)
+
+Notes:
+ psz can be null but the function will fail
+
+ cbMax should be greater than or equal to sizeof(TCHAR) or the function will fail
+
+Return Value:
+
+ S_OK - psz is non-null and the length including the null
+ terminator is less than or equal to cbMax bytes
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function.
+
+--*/
+
+STRSAFEAPI StringCbLengthA(const char* psz, size_t cchMax, size_t* pcch);
+STRSAFEAPI StringCbLengthW(const wchar_t* psz, size_t cchMax, size_t* pcch);
+#ifdef UNICODE
+#define StringCbLength StringCbLengthW
+#else
+#define StringCbLength StringCbLengthA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbLengthA(const char* psz, size_t cbMax, size_t* pcb)
+{
+ HRESULT hr;
+ size_t cchMax;
+ size_t cch = 0;
+
+ cchMax = cbMax / sizeof(char);
+
+ if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringLengthWorkerA(psz, cchMax, &cch);
+ }
+
+ if (SUCCEEDED(hr) && pcb)
+ {
+ // safe to multiply cch * sizeof(char) since cch < STRSAFE_MAX_CCH and sizeof(char) is 1
+ *pcb = cch * sizeof(char);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCbLengthW(const wchar_t* psz, size_t cbMax, size_t* pcb)
+{
+ HRESULT hr;
+ size_t cchMax;
+ size_t cch = 0;
+
+ cchMax = cbMax / sizeof(wchar_t);
+
+ if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringLengthWorkerW(psz, cchMax, &cch);
+ }
+
+ if (SUCCEEDED(hr) && pcb)
+ {
+ // safe to multiply cch * sizeof(wchar_t) since cch < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
+ *pcb = cch * sizeof(wchar_t);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+// these are the worker functions that actually do the work
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCopyWorkerA(char* pszDest, size_t cchDest, const char* pszSrc)
+{
+ HRESULT hr = S_OK;
+
+ if (cchDest == 0)
+ {
+ // can not null terminate a zero-byte dest buffer
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ while (cchDest && (*pszSrc != '\0'))
+ {
+ *pszDest++ = *pszSrc++;
+ cchDest--;
+ }
+
+ if (cchDest == 0)
+ {
+ // we are going to truncate pszDest
+ pszDest--;
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+
+ *pszDest= '\0';
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCopyWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc)
+{
+ HRESULT hr = S_OK;
+
+ if (cchDest == 0)
+ {
+ // can not null terminate a zero-byte dest buffer
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ while (cchDest && (*pszSrc != L'\0'))
+ {
+ *pszDest++ = *pszSrc++;
+ cchDest--;
+ }
+
+ if (cchDest == 0)
+ {
+ // we are going to truncate pszDest
+ pszDest--;
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+
+ *pszDest= L'\0';
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCopyExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr = S_OK;
+ char* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+
+ // ASSERT(cbDest == (cchDest * sizeof(char)) ||
+ // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest != 0) || (cbDest != 0))
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+
+ if (pszSrc == NULL)
+ {
+ pszSrc = "";
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = 0;
+
+ // only fail if there was actually src data to copy
+ if (*pszSrc != '\0')
+ {
+ if (pszDest == NULL)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ else
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ while (cchRemaining && (*pszSrc != '\0'))
+ {
+ *pszDestEnd++= *pszSrc++;
+ cchRemaining--;
+ }
+
+ if (cchRemaining > 0)
+ {
+ if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
+ {
+ memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(char)) + (cbDest % sizeof(char)));
+ }
+ }
+ else
+ {
+ // we are going to truncate pszDest
+ pszDestEnd--;
+ cchRemaining++;
+
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+
+ *pszDestEnd = '\0';
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = '\0';
+ }
+ }
+
+ if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = '\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCopyExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr = S_OK;
+ wchar_t* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+
+ // ASSERT(cbDest == (cchDest * sizeof(wchar_t)) ||
+ // cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest != 0) || (cbDest != 0))
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+
+ if (pszSrc == NULL)
+ {
+ pszSrc = L"";
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = 0;
+
+ // only fail if there was actually src data to copy
+ if (*pszSrc != L'\0')
+ {
+ if (pszDest == NULL)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ else
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ while (cchRemaining && (*pszSrc != L'\0'))
+ {
+ *pszDestEnd++= *pszSrc++;
+ cchRemaining--;
+ }
+
+ if (cchRemaining > 0)
+ {
+ if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
+ {
+ memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
+ }
+ }
+ else
+ {
+ // we are going to truncate pszDest
+ pszDestEnd--;
+ cchRemaining++;
+
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+
+ *pszDestEnd = L'\0';
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+
+ if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCopyNWorkerA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc)
+{
+ HRESULT hr = S_OK;
+
+ if (cchDest == 0)
+ {
+ // can not null terminate a zero-byte dest buffer
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ while (cchDest && cchSrc && (*pszSrc != '\0'))
+ {
+ *pszDest++= *pszSrc++;
+ cchDest--;
+ cchSrc--;
+ }
+
+ if (cchDest == 0)
+ {
+ // we are going to truncate pszDest
+ pszDest--;
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+
+ *pszDest= '\0';
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCopyNWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc)
+{
+ HRESULT hr = S_OK;
+
+ if (cchDest == 0)
+ {
+ // can not null terminate a zero-byte dest buffer
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ while (cchDest && cchSrc && (*pszSrc != L'\0'))
+ {
+ *pszDest++= *pszSrc++;
+ cchDest--;
+ cchSrc--;
+ }
+
+ if (cchDest == 0)
+ {
+ // we are going to truncate pszDest
+ pszDest--;
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+
+ *pszDest= L'\0';
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCopyNExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, size_t cchSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr = S_OK;
+ char* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+
+ // ASSERT(cbDest == (cchDest * sizeof(char)) ||
+ // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest != 0) || (cbDest != 0))
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+
+ if (pszSrc == NULL)
+ {
+ pszSrc = "";
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = 0;
+
+ // only fail if there was actually src data to copy
+ if (*pszSrc != '\0')
+ {
+ if (pszDest == NULL)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ else
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ while (cchRemaining && cchSrc && (*pszSrc != '\0'))
+ {
+ *pszDestEnd++= *pszSrc++;
+ cchRemaining--;
+ cchSrc--;
+ }
+
+ if (cchRemaining > 0)
+ {
+ if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
+ {
+ memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(char)) + (cbDest % sizeof(char)));
+ }
+ }
+ else
+ {
+ // we are going to truncate pszDest
+ pszDestEnd--;
+ cchRemaining++;
+
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+
+ *pszDestEnd = '\0';
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = '\0';
+ }
+ }
+
+ if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = '\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCopyNExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, size_t cchSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr = S_OK;
+ wchar_t* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+
+ // ASSERT(cbDest == (cchDest * sizeof(wchar_t)) ||
+ // cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest != 0) || (cbDest != 0))
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+
+ if (pszSrc == NULL)
+ {
+ pszSrc = L"";
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = 0;
+
+ // only fail if there was actually src data to copy
+ if (*pszSrc != L'\0')
+ {
+ if (pszDest == NULL)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ else
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ while (cchRemaining && cchSrc && (*pszSrc != L'\0'))
+ {
+ *pszDestEnd++= *pszSrc++;
+ cchRemaining--;
+ cchSrc--;
+ }
+
+ if (cchRemaining > 0)
+ {
+ if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
+ {
+ memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
+ }
+ }
+ else
+ {
+ // we are going to truncate pszDest
+ pszDestEnd--;
+ cchRemaining++;
+
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+
+ *pszDestEnd = L'\0';
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+
+ if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCatWorkerA(char* pszDest, size_t cchDest, const char* pszSrc)
+{
+ HRESULT hr;
+ size_t cchDestCurrent;
+
+ hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = StringCopyWorkerA(pszDest + cchDestCurrent,
+ cchDest - cchDestCurrent,
+ pszSrc);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCatWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc)
+{
+ HRESULT hr;
+ size_t cchDestCurrent;
+
+ hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = StringCopyWorkerW(pszDest + cchDestCurrent,
+ cchDest - cchDestCurrent,
+ pszSrc);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCatExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr = S_OK;
+ char* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+
+ // ASSERT(cbDest == (cchDest * sizeof(char)) ||
+ // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cchDestCurrent;
+
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest == 0) && (cbDest == 0))
+ {
+ cchDestCurrent = 0;
+ }
+ else
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+ else
+ {
+ hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ pszDestEnd = pszDest + cchDestCurrent;
+ cchRemaining = cchDest - cchDestCurrent;
+ }
+ }
+
+ if (pszSrc == NULL)
+ {
+ pszSrc = "";
+ }
+ }
+ else
+ {
+ hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ pszDestEnd = pszDest + cchDestCurrent;
+ cchRemaining = cchDest - cchDestCurrent;
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest == 0)
+ {
+ // only fail if there was actually src data to append
+ if (*pszSrc != '\0')
+ {
+ if (pszDest == NULL)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ else
+ {
+ // we handle the STRSAFE_FILL_ON_FAILURE and STRSAFE_NULL_ON_FAILURE cases below, so do not pass
+ // those flags through
+ hr = StringCopyExWorkerA(pszDestEnd,
+ cchRemaining,
+ (cchRemaining * sizeof(char)) + (cbDest % sizeof(char)),
+ pszSrc,
+ &pszDestEnd,
+ &cchRemaining,
+ dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)));
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ // STRSAFE_NO_TRUNCATION is taken care of by StringCopyExWorkerA()
+
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = '\0';
+ }
+ }
+
+ if (dwFlags & STRSAFE_NULL_ON_FAILURE)
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = '\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCatExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr = S_OK;
+ wchar_t* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+
+ // ASSERT(cbDest == (cchDest * sizeof(wchar_t)) ||
+ // cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cchDestCurrent;
+
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest == 0) && (cbDest == 0))
+ {
+ cchDestCurrent = 0;
+ }
+ else
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+ else
+ {
+ hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ pszDestEnd = pszDest + cchDestCurrent;
+ cchRemaining = cchDest - cchDestCurrent;
+ }
+ }
+
+ if (pszSrc == NULL)
+ {
+ pszSrc = L"";
+ }
+ }
+ else
+ {
+ hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ pszDestEnd = pszDest + cchDestCurrent;
+ cchRemaining = cchDest - cchDestCurrent;
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest == 0)
+ {
+ // only fail if there was actually src data to append
+ if (*pszSrc != L'\0')
+ {
+ if (pszDest == NULL)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ else
+ {
+ // we handle the STRSAFE_FILL_ON_FAILURE and STRSAFE_NULL_ON_FAILURE cases below, so do not pass
+ // those flags through
+ hr = StringCopyExWorkerW(pszDestEnd,
+ cchRemaining,
+ (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)),
+ pszSrc,
+ &pszDestEnd,
+ &cchRemaining,
+ dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)));
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ // STRSAFE_NO_TRUNCATION is taken care of by StringCopyExWorkerW()
+
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+
+ if (dwFlags & STRSAFE_NULL_ON_FAILURE)
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCatNWorkerA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend)
+{
+ HRESULT hr;
+ size_t cchDestCurrent;
+
+ hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = StringCopyNWorkerA(pszDest + cchDestCurrent,
+ cchDest - cchDestCurrent,
+ pszSrc,
+ cchMaxAppend);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCatNWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend)
+{
+ HRESULT hr;
+ size_t cchDestCurrent;
+
+ hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = StringCopyNWorkerW(pszDest + cchDestCurrent,
+ cchDest - cchDestCurrent,
+ pszSrc,
+ cchMaxAppend);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCatNExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, size_t cchMaxAppend, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr = S_OK;
+ char* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+ size_t cchDestCurrent = 0;
+
+ // ASSERT(cbDest == (cchDest * sizeof(char)) ||
+ // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest == 0) && (cbDest == 0))
+ {
+ cchDestCurrent = 0;
+ }
+ else
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+ else
+ {
+ hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ pszDestEnd = pszDest + cchDestCurrent;
+ cchRemaining = cchDest - cchDestCurrent;
+ }
+ }
+
+ if (pszSrc == NULL)
+ {
+ pszSrc = "";
+ }
+ }
+ else
+ {
+ hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ pszDestEnd = pszDest + cchDestCurrent;
+ cchRemaining = cchDest - cchDestCurrent;
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest == 0)
+ {
+ // only fail if there was actually src data to append
+ if (*pszSrc != '\0')
+ {
+ if (pszDest == NULL)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ else
+ {
+ // we handle the STRSAFE_FILL_ON_FAILURE and STRSAFE_NULL_ON_FAILURE cases below, so do not pass
+ // those flags through
+ hr = StringCopyNExWorkerA(pszDestEnd,
+ cchRemaining,
+ (cchRemaining * sizeof(char)) + (cbDest % sizeof(char)),
+ pszSrc,
+ cchMaxAppend,
+ &pszDestEnd,
+ &cchRemaining,
+ dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)));
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ // STRSAFE_NO_TRUNCATION is taken care of by StringCopyNExWorkerA()
+
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = '\0';
+ }
+ }
+
+ if (dwFlags & (STRSAFE_NULL_ON_FAILURE))
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = '\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCatNExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, size_t cchMaxAppend, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr = S_OK;
+ wchar_t* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+ size_t cchDestCurrent = 0;
+
+
+ // ASSERT(cbDest == (cchDest * sizeof(wchar_t)) ||
+ // cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest == 0) && (cbDest == 0))
+ {
+ cchDestCurrent = 0;
+ }
+ else
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+ else
+ {
+ hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ pszDestEnd = pszDest + cchDestCurrent;
+ cchRemaining = cchDest - cchDestCurrent;
+ }
+ }
+
+ if (pszSrc == NULL)
+ {
+ pszSrc = L"";
+ }
+ }
+ else
+ {
+ hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ pszDestEnd = pszDest + cchDestCurrent;
+ cchRemaining = cchDest - cchDestCurrent;
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest == 0)
+ {
+ // only fail if there was actually src data to append
+ if (*pszSrc != L'\0')
+ {
+ if (pszDest == NULL)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ else
+ {
+ // we handle the STRSAFE_FILL_ON_FAILURE and STRSAFE_NULL_ON_FAILURE cases below, so do not pass
+ // those flags through
+ hr = StringCopyNExWorkerW(pszDestEnd,
+ cchRemaining,
+ (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)),
+ pszSrc,
+ cchMaxAppend,
+ &pszDestEnd,
+ &cchRemaining,
+ dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)));
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ // STRSAFE_NO_TRUNCATION is taken care of by StringCopyNExWorkerW()
+
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+
+ if (dwFlags & (STRSAFE_NULL_ON_FAILURE))
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringVPrintfWorkerA(char* pszDest, size_t cchDest, const char* pszFormat, va_list argList)
+{
+ HRESULT hr = S_OK;
+
+ if (cchDest == 0)
+ {
+ // can not null terminate a zero-byte dest buffer
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ int iRet;
+ size_t cchMax;
+
+ // leave the last space for the null terminator
+ cchMax = cchDest - 1;
+
+ iRet = _vsnprintf(pszDest, cchMax, pszFormat, argList);
+ // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax));
+
+ if ((iRet < 0) || (((size_t)iRet) > cchMax))
+ {
+ // need to null terminate the string
+ pszDest += cchMax;
+ *pszDest = '\0';
+
+ // we have truncated pszDest
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ else if (((size_t)iRet) == cchMax)
+ {
+ // need to null terminate the string
+ pszDest += cchMax;
+ *pszDest = '\0';
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringVPrintfWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, va_list argList)
+{
+ HRESULT hr = S_OK;
+
+ if (cchDest == 0)
+ {
+ // can not null terminate a zero-byte dest buffer
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ int iRet;
+ size_t cchMax;
+
+ // leave the last space for the null terminator
+ cchMax = cchDest - 1;
+
+ iRet = _vsnwprintf(pszDest, cchMax, pszFormat, argList);
+ // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax));
+
+ if ((iRet < 0) || (((size_t)iRet) > cchMax))
+ {
+ // need to null terminate the string
+ pszDest += cchMax;
+ *pszDest = L'\0';
+
+ // we have truncated pszDest
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ else if (((size_t)iRet) == cchMax)
+ {
+ // need to null terminate the string
+ pszDest += cchMax;
+ *pszDest = L'\0';
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringVPrintfExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList)
+{
+ HRESULT hr = S_OK;
+ char* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+
+ // ASSERT(cbDest == (cchDest * sizeof(char)) ||
+ // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest != 0) || (cbDest != 0))
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+
+ if (pszFormat == NULL)
+ {
+ pszFormat = "";
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = 0;
+
+ // only fail if there was actually a non-empty format string
+ if (*pszFormat != '\0')
+ {
+ if (pszDest == NULL)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ else
+ {
+ int iRet;
+ size_t cchMax;
+
+ // leave the last space for the null terminator
+ cchMax = cchDest - 1;
+
+ iRet = _vsnprintf(pszDest, cchMax, pszFormat, argList);
+ // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax));
+
+ if ((iRet < 0) || (((size_t)iRet) > cchMax))
+ {
+ // we have truncated pszDest
+ pszDestEnd = pszDest + cchMax;
+ cchRemaining = 1;
+
+ // need to null terminate the string
+ *pszDestEnd = '\0';
+
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ else if (((size_t)iRet) == cchMax)
+ {
+ // string fit perfectly
+ pszDestEnd = pszDest + cchMax;
+ cchRemaining = 1;
+
+ // need to null terminate the string
+ *pszDestEnd = '\0';
+ }
+ else if (((size_t)iRet) < cchMax)
+ {
+ // there is extra room
+ pszDestEnd = pszDest + iRet;
+ cchRemaining = cchDest - iRet;
+
+ if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
+ {
+ memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(char)) + (cbDest % sizeof(char)));
+ }
+ }
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = '\0';
+ }
+ }
+
+ if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = '\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringVPrintfExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList)
+{
+ HRESULT hr = S_OK;
+ wchar_t* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+
+ // ASSERT(cbDest == (cchDest * sizeof(wchar_t)) ||
+ // cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest != 0) || (cbDest != 0))
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+
+ if (pszFormat == NULL)
+ {
+ pszFormat = L"";
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = 0;
+
+ // only fail if there was actually a non-empty format string
+ if (*pszFormat != L'\0')
+ {
+ if (pszDest == NULL)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ else
+ {
+ int iRet;
+ size_t cchMax;
+
+ // leave the last space for the null terminator
+ cchMax = cchDest - 1;
+
+ iRet = _vsnwprintf(pszDest, cchMax, pszFormat, argList);
+ // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax));
+
+ if ((iRet < 0) || (((size_t)iRet) > cchMax))
+ {
+ // we have truncated pszDest
+ pszDestEnd = pszDest + cchMax;
+ cchRemaining = 1;
+
+ // need to null terminate the string
+ *pszDestEnd = L'\0';
+
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ else if (((size_t)iRet) == cchMax)
+ {
+ // string fit perfectly
+ pszDestEnd = pszDest + cchMax;
+ cchRemaining = 1;
+
+ // need to null terminate the string
+ *pszDestEnd = L'\0';
+ }
+ else if (((size_t)iRet) < cchMax)
+ {
+ // there is extra room
+ pszDestEnd = pszDest + iRet;
+ cchRemaining = cchDest - iRet;
+
+ if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
+ {
+ memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
+ }
+ }
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+
+ if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringLengthWorkerA(const char* psz, size_t cchMax, size_t* pcch)
+{
+ HRESULT hr = S_OK;
+ size_t cchMaxPrev = cchMax;
+
+ while (cchMax && (*psz != '\0'))
+ {
+ psz++;
+ cchMax--;
+ }
+
+ if (cchMax == 0)
+ {
+ // the string is longer than cchMax
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+
+ if (SUCCEEDED(hr) && pcch)
+ {
+ *pcch = cchMaxPrev - cchMax;
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringLengthWorkerW(const wchar_t* psz, size_t cchMax, size_t* pcch)
+{
+ HRESULT hr = S_OK;
+ size_t cchMaxPrev = cchMax;
+
+ while (cchMax && (*psz != L'\0'))
+ {
+ psz++;
+ cchMax--;
+ }
+
+ if (cchMax == 0)
+ {
+ // the string is longer than cchMax
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+
+ if (SUCCEEDED(hr) && pcch)
+ {
+ *pcch = cchMaxPrev - cchMax;
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+
+#ifndef STRSAFE_LIB_IMPL
+STRSAFE_INLINE_API StringGetsExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr = S_OK;
+ char* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+
+ // ASSERT(cbDest == (cchDest * sizeof(char)) ||
+ // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest != 0) || (cbDest != 0))
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest <= 1)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ if (cchDest == 1)
+ {
+ *pszDestEnd = '\0';
+ }
+
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ else
+ {
+ char ch;
+
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ while ((cchRemaining > 1) && (ch = (char)getc(stdin)) != '\n')
+ {
+ if (ch == EOF)
+ {
+ if (pszDestEnd == pszDest)
+ {
+ // we failed to read anything from stdin
+ hr = STRSAFE_E_END_OF_FILE;
+ }
+ break;
+ }
+
+ *pszDestEnd = ch;
+
+ pszDestEnd++;
+ cchRemaining--;
+ }
+
+ if (cchRemaining > 0)
+ {
+ // there is extra room
+ if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
+ {
+ memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(char)) + (cbDest % sizeof(char)));
+ }
+ }
+
+ *pszDestEnd = '\0';
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = '\0';
+ }
+ }
+
+ if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = '\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) ||
+ (hr == STRSAFE_E_INSUFFICIENT_BUFFER) ||
+ (hr == STRSAFE_E_END_OF_FILE))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+
+STRSAFE_INLINE_API StringGetsExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr = S_OK;
+ wchar_t* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+
+ // ASSERT(cbDest == (cchDest * sizeof(char)) ||
+ // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest != 0) || (cbDest != 0))
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest <= 1)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ if (cchDest == 1)
+ {
+ *pszDestEnd = L'\0';
+ }
+
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ else
+ {
+ wchar_t ch;
+
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ while ((cchRemaining > 1) && (ch = (wchar_t)getwc(stdin)) != L'\n')
+ {
+ if (ch == EOF)
+ {
+ if (pszDestEnd == pszDest)
+ {
+ // we failed to read anything from stdin
+ hr = STRSAFE_E_END_OF_FILE;
+ }
+ break;
+ }
+
+ *pszDestEnd = ch;
+
+ pszDestEnd++;
+ cchRemaining--;
+ }
+
+ if (cchRemaining > 0)
+ {
+ // there is extra room
+ if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
+ {
+ memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
+ }
+ }
+
+ *pszDestEnd = L'\0';
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+
+ if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) ||
+ (hr == STRSAFE_E_INSUFFICIENT_BUFFER) ||
+ (hr == STRSAFE_E_END_OF_FILE))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+#endif // !STRSAFE_LIB_IMPL
+
+
+// Do not call these functions, they are worker functions for internal use within this file
+#ifdef DEPRECATE_SUPPORTED
+#pragma deprecated(StringCopyWorkerA)
+#pragma deprecated(StringCopyWorkerW)
+#pragma deprecated(StringCopyExWorkerA)
+#pragma deprecated(StringCopyExWorkerW)
+#pragma deprecated(StringCatWorkerA)
+#pragma deprecated(StringCatWorkerW)
+#pragma deprecated(StringCatExWorkerA)
+#pragma deprecated(StringCatExWorkerW)
+#pragma deprecated(StringCatNWorkerA)
+#pragma deprecated(StringCatNWorkerW)
+#pragma deprecated(StringCatNExWorkerA)
+#pragma deprecated(StringCatNExWorkerW)
+#pragma deprecated(StringVPrintfWorkerA)
+#pragma deprecated(StringVPrintfWorkerW)
+#pragma deprecated(StringVPrintfExWorkerA)
+#pragma deprecated(StringVPrintfExWorkerW)
+#pragma deprecated(StringLengthWorkerA)
+#pragma deprecated(StringLengthWorkerW)
+#else
+#define StringCopyWorkerA StringCopyWorkerA_instead_use_StringCchCopyA_or_StringCchCopyExA;
+#define StringCopyWorkerW StringCopyWorkerW_instead_use_StringCchCopyW_or_StringCchCopyExW;
+#define StringCopyExWorkerA StringCopyExWorkerA_instead_use_StringCchCopyA_or_StringCchCopyExA;
+#define StringCopyExWorkerW StringCopyExWorkerW_instead_use_StringCchCopyW_or_StringCchCopyExW;
+#define StringCatWorkerA StringCatWorkerA_instead_use_StringCchCatA_or_StringCchCatExA;
+#define StringCatWorkerW StringCatWorkerW_instead_use_StringCchCatW_or_StringCchCatExW;
+#define StringCatExWorkerA StringCatExWorkerA_instead_use_StringCchCatA_or_StringCchCatExA;
+#define StringCatExWorkerW StringCatExWorkerW_instead_use_StringCchCatW_or_StringCchCatExW;
+#define StringCatNWorkerA StringCatNWorkerA_instead_use_StringCchCatNA_or_StrincCbCatNA;
+#define StringCatNWorkerW StringCatNWorkerW_instead_use_StringCchCatNW_or_StringCbCatNW;
+#define StringCatNExWorkerA StringCatNExWorkerA_instead_use_StringCchCatNExA_or_StringCbCatNExA;
+#define StringCatNExWorkerW StringCatNExWorkerW_instead_use_StringCchCatNExW_or_StringCbCatNExW;
+#define StringVPrintfWorkerA StringVPrintfWorkerA_instead_use_StringCchVPrintfA_or_StringCchVPrintfExA;
+#define StringVPrintfWorkerW StringVPrintfWorkerW_instead_use_StringCchVPrintfW_or_StringCchVPrintfExW;
+#define StringVPrintfExWorkerA StringVPrintfExWorkerA_instead_use_StringCchVPrintfA_or_StringCchVPrintfExA;
+#define StringVPrintfExWorkerW StringVPrintfExWorkerW_instead_use_StringCchVPrintfW_or_StringCchVPrintfExW;
+#define StringLengthWorkerA StringLengthWorkerA_instead_use_StringCchLengthA_or_StringCbLengthA;
+#define StringLengthWorkerW StringLengthWorkerW_instead_use_StringCchLengthW_or_StringCbLengthW;
+#endif // !DEPRECATE_SUPPORTED
+
+
+#ifndef STRSAFE_NO_DEPRECATE
+// Deprecate all of the unsafe functions to generate compiletime errors. If you do not want
+// this then you can #define STRSAFE_NO_DEPRECATE before including this file.
+#ifdef DEPRECATE_SUPPORTED
+
+// First all the names that are a/w variants (or shouldn't be #defined by now anyway).
+#pragma deprecated(lstrcpyA)
+#pragma deprecated(lstrcpyW)
+#pragma deprecated(lstrcatA)
+#pragma deprecated(lstrcatW)
+#pragma deprecated(wsprintfA)
+#pragma deprecated(wsprintfW)
+
+#pragma deprecated(StrCpyW)
+#pragma deprecated(StrCatW)
+#pragma deprecated(StrNCatA)
+#pragma deprecated(StrNCatW)
+#pragma deprecated(StrCatNA)
+#pragma deprecated(StrCatNW)
+#pragma deprecated(wvsprintfA)
+#pragma deprecated(wvsprintfW)
+
+#pragma deprecated(strcpy)
+#pragma deprecated(wcscpy)
+#pragma deprecated(strcat)
+#pragma deprecated(wcscat)
+#pragma deprecated(sprintf)
+#pragma deprecated(swprintf)
+#pragma deprecated(vsprintf)
+#pragma deprecated(vswprintf)
+#pragma deprecated(_snprintf)
+#pragma deprecated(_snwprintf)
+#pragma deprecated(_vsnprintf)
+#pragma deprecated(_vsnwprintf)
+#pragma deprecated(gets)
+#pragma deprecated(_getws)
+
+// Then all the windows.h names - we need to undef and redef based on UNICODE setting
+#undef lstrcpy
+#undef lstrcat
+#undef wsprintf
+#undef wvsprintf
+#pragma deprecated(lstrcpy)
+#pragma deprecated(lstrcat)
+#pragma deprecated(wsprintf)
+#pragma deprecated(wvsprintf)
+#ifdef UNICODE
+#define lstrcpy lstrcpyW
+#define lstrcat lstrcatW
+#define wsprintf wsprintfW
+#define wvsprintf wvsprintfW
+#else
+#define lstrcpy lstrcpyA
+#define lstrcat lstrcatA
+#define wsprintf wsprintfA
+#define wvsprintf wvsprintfA
+#endif
+
+// Then the shlwapi names - they key off UNICODE also.
+#undef StrCpyA
+#undef StrCpy
+#undef StrCatA
+#undef StrCat
+#undef StrNCat
+#undef StrCatN
+#pragma deprecated(StrCpyA)
+#pragma deprecated(StrCatA)
+#pragma deprecated(StrCatN)
+#pragma deprecated(StrCpy)
+#pragma deprecated(StrCat)
+#pragma deprecated(StrNCat)
+#define StrCpyA lstrcpyA
+#define StrCatA lstrcatA
+#define StrCatN StrNCat
+#ifdef UNICODE
+#define StrCpy StrCpyW
+#define StrCat StrCatW
+#define StrNCat StrNCatW
+#else
+#define StrCpy lstrcpyA
+#define StrCat lstrcatA
+#define StrNCat StrNCatA
+#endif
+
+// Then all the CRT names - we need to undef/redef based on _UNICODE value.
+#undef _tcscpy
+#undef _ftcscpy
+#undef _tcscat
+#undef _ftcscat
+#undef _stprintf
+#undef _sntprintf
+#undef _vstprintf
+#undef _vsntprintf
+#undef _getts
+#pragma deprecated(_tcscpy)
+#pragma deprecated(_ftcscpy)
+#pragma deprecated(_tcscat)
+#pragma deprecated(_ftcscat)
+#pragma deprecated(_stprintf)
+#pragma deprecated(_sntprintf)
+#pragma deprecated(_vstprintf)
+#pragma deprecated(_vsntprintf)
+#pragma deprecated(_getts)
+#ifdef _UNICODE
+#define _tcscpy wcscpy
+#define _ftcscpy wcscpy
+#define _tcscat wcscat
+#define _ftcscat wcscat
+#define _stprintf swprintf
+#define _sntprintf _snwprintf
+#define _vstprintf vswprintf
+#define _vsntprintf _vsnwprintf
+#define _getts _getws
+#else
+#define _tcscpy strcpy
+#define _ftcscpy strcpy
+#define _tcscat strcat
+#define _ftcscat strcat
+#define _stprintf sprintf
+#define _sntprintf _snprintf
+#define _vstprintf vsprintf
+#define _vsntprintf _vsnprintf
+#define _getts gets
+#endif
+
+#else // DEPRECATE_SUPPORTED
+
+#undef strcpy
+#define strcpy strcpy_instead_use_StringCbCopyA_or_StringCchCopyA;
+
+#undef wcscpy
+#define wcscpy wcscpy_instead_use_StringCbCopyW_or_StringCchCopyW;
+
+#undef strcat
+#define strcat strcat_instead_use_StringCbCatA_or_StringCchCatA;
+
+#undef wcscat
+#define wcscat wcscat_instead_use_StringCbCatW_or_StringCchCatW;
+
+#undef sprintf
+#define sprintf sprintf_instead_use_StringCbPrintfA_or_StringCchPrintfA;
+
+#undef swprintf
+#define swprintf swprintf_instead_use_StringCbPrintfW_or_StringCchPrintfW;
+
+#undef vsprintf
+#define vsprintf vsprintf_instead_use_StringCbVPrintfA_or_StringCchVPrintfA;
+
+#undef vswprintf
+#define vswprintf vswprintf_instead_use_StringCbVPrintfW_or_StringCchVPrintfW;
+
+#undef _snprintf
+#define _snprintf _snprintf_instead_use_StringCbPrintfA_or_StringCchPrintfA;
+
+#undef _snwprintf
+#define _snwprintf _snwprintf_instead_use_StringCbPrintfW_or_StringCchPrintfW;
+
+#undef _vsnprintf
+#define _vsnprintf _vsnprintf_instead_use_StringCbVPrintfA_or_StringCchVPrintfA;
+
+#undef _vsnwprintf
+#define _vsnwprintf _vsnwprintf_instead_use_StringCbVPrintfW_or_StringCchVPrintfW;
+
+#undef strcpyA
+#define strcpyA strcpyA_instead_use_StringCbCopyA_or_StringCchCopyA;
+
+#undef strcpyW
+#define strcpyW strcpyW_instead_use_StringCbCopyW_or_StringCchCopyW;
+
+#undef lstrcpy
+#define lstrcpy lstrcpy_instead_use_StringCbCopy_or_StringCchCopy;
+
+#undef lstrcpyA
+#define lstrcpyA lstrcpyA_instead_use_StringCbCopyA_or_StringCchCopyA;
+
+#undef lstrcpyW
+#define lstrcpyW lstrcpyW_instead_use_StringCbCopyW_or_StringCchCopyW;
+
+#undef StrCpy
+#define StrCpy StrCpy_instead_use_StringCbCopy_or_StringCchCopy;
+
+#undef StrCpyA
+#define StrCpyA StrCpyA_instead_use_StringCbCopyA_or_StringCchCopyA;
+
+#undef StrCpyW
+#define StrCpyW StrCpyW_instead_use_StringCbCopyW_or_StringCchCopyW;
+
+#undef _tcscpy
+#define _tcscpy _tcscpy_instead_use_StringCbCopy_or_StringCchCopy;
+
+#undef _ftcscpy
+#define _ftcscpy _ftcscpy_instead_use_StringCbCopy_or_StringCchCopy;
+
+#undef lstrcat
+#define lstrcat lstrcat_instead_use_StringCbCat_or_StringCchCat;
+
+#undef lstrcatA
+#define lstrcatA lstrcatA_instead_use_StringCbCatA_or_StringCchCatA;
+
+#undef lstrcatW
+#define lstrcatW lstrcatW_instead_use_StringCbCatW_or_StringCchCatW;
+
+#undef StrCat
+#define StrCat StrCat_instead_use_StringCbCat_or_StringCchCat;
+
+#undef StrCatA
+#define StrCatA StrCatA_instead_use_StringCbCatA_or_StringCchCatA;
+
+#undef StrCatW
+#define StrCatW StrCatW_instead_use_StringCbCatW_or_StringCchCatW;
+
+#undef StrNCat
+#define StrNCat StrNCat_instead_use_StringCbCatN_or_StringCchCatN;
+
+#undef StrNCatA
+#define StrNCatA StrNCatA_instead_use_StringCbCatNA_or_StringCchCatNA;
+
+#undef StrNCatW
+#define StrNCatW StrNCatW_instead_use_StringCbCatNW_or_StringCchCatNW;
+
+#undef StrCatN
+#define StrCatN StrCatN_instead_use_StringCbCatN_or_StringCchCatN;
+
+#undef StrCatNA
+#define StrCatNA StrCatNA_instead_use_StringCbCatNA_or_StringCchCatNA;
+
+#undef StrCatNW
+#define StrCatNW StrCatNW_instead_use_StringCbCatNW_or_StringCchCatNW;
+
+#undef _tcscat
+#define _tcscat _tcscat_instead_use_StringCbCat_or_StringCchCat;
+
+#undef _ftcscat
+#define _ftcscat _ftcscat_instead_use_StringCbCat_or_StringCchCat;
+
+#undef wsprintf
+#define wsprintf wsprintf_instead_use_StringCbPrintf_or_StringCchPrintf;
+
+#undef wsprintfA
+#define wsprintfA wsprintfA_instead_use_StringCbPrintfA_or_StringCchPrintfA;
+
+#undef wsprintfW
+#define wsprintfW wsprintfW_instead_use_StringCbPrintfW_or_StringCchPrintfW;
+
+#undef wvsprintf
+#define wvsprintf wvsprintf_instead_use_StringCbVPrintf_or_StringCchVPrintf;
+
+#undef wvsprintfA
+#define wvsprintfA wvsprintfA_instead_use_StringCbVPrintfA_or_StringCchVPrintfA;
+
+#undef wvsprintfW
+#define wvsprintfW wvsprintfW_instead_use_StringCbVPrintfW_or_StringCchVPrintfW;
+
+#undef _vstprintf
+#define _vstprintf _vstprintf_instead_use_StringCbVPrintf_or_StringCchVPrintf;
+
+#undef _vsntprintf
+#define _vsntprintf _vsntprintf_instead_use_StringCbVPrintf_or_StringCchVPrintf;
+
+#undef _stprintf
+#define _stprintf _stprintf_instead_use_StringCbPrintf_or_StringCchPrintf;
+
+#undef _sntprintf
+#define _sntprintf _sntprintf_instead_use_StringCbPrintf_or_StringCchPrintf;
+
+#undef _getts
+#define _getts _getts_instead_use_StringCbGets_or_StringCchGets;
+
+#undef gets
+#define gets _gets_instead_use_StringCbGetsA_or_StringCchGetsA;
+
+#undef _getws
+#define _getws _getws_instead_use_StringCbGetsW_or_StringCchGetsW;
+
+#endif // !DEPRECATE_SUPPORTED
+#endif // !STRSAFE_NO_DEPRECATE
+
+#ifdef _NTSTRSAFE_H_INCLUDED_
+#pragma warning(pop)
+#endif // _NTSTRSAFE_H_INCLUDED_
+
+#endif // _STRSAFE_H_INCLUDED_
diff --git a/cpp/Pipe/src/pipe.c b/cpp/Pipe/src/pipe.c
new file mode 100644
index 0000000..c83c76d
--- /dev/null
+++ b/cpp/Pipe/src/pipe.c
@@ -0,0 +1,262 @@
+#include
+#include
+#include
+#include "pipe.h"
+
+#define DEBUG 0
+
+JNIEXPORT jint JNICALL Java_pipe_Pipes_CreateNamedPipe
+(
+ JNIEnv *env,
+ jclass className,
+ jstring sPipeName,
+ jint dwOpenMode,
+ jint dwPipeMode,
+ jint nMaxInstances,
+ jint nOutBufferSize,
+ jint nInBufferSize,
+ jint nDefaultTimeOut,
+ jint lpSecurityAttributes
+ )
+{
+ HANDLE pipeHandler;
+ LPCSTR pipeName;
+ pipeName = (*env)->GetStringUTFChars(env, sPipeName, NULL);
+ if (pipeName == NULL)
+ return -1;
+
+ if (DEBUG)
+ {
+ printf("Native: Pipe Name %s\n", pipeName);
+ printf("Native: dwOpenMode %d\n", dwOpenMode);
+ printf("Native: dwPipeMode %d\n", dwPipeMode);
+ printf("Native: nMaxInstances %d\n", nMaxInstances);
+ printf("Native: nOutBufferSize %d\n", nOutBufferSize);
+ printf("Native: nInBufferSize %d\n", nInBufferSize);
+ printf("Native: nDefaultTimeOut %d\n", nDefaultTimeOut);
+ }
+
+ pipeHandler = CreateNamedPipe((LPCSTR)pipeName, dwOpenMode, dwPipeMode, nMaxInstances, nOutBufferSize, nInBufferSize,
+ nDefaultTimeOut, (LPSECURITY_ATTRIBUTES) lpSecurityAttributes);
+
+ (*env)->ReleaseStringUTFChars(env, sPipeName, pipeName);
+ return (jint) pipeHandler;
+}
+
+JNIEXPORT jboolean JNICALL Java_pipe_Pipes_ConnectNamedPipe
+(
+ JNIEnv *env,
+ jclass className,
+ jint hNamedPipe,
+ jint lpOverlapped
+ )
+{
+ BOOL fConnected;
+ HANDLE pipeHandler = (HANDLE) hNamedPipe;
+ fConnected = ConnectNamedPipe(pipeHandler, (LPOVERLAPPED) lpOverlapped);
+ return fConnected;
+}
+
+JNIEXPORT jint JNICALL Java_pipe_Pipes_GetLastError
+(
+ JNIEnv *env,
+ jclass className
+ )
+{
+ DWORD errorNumber = GetLastError();
+ return (jint) errorNumber;
+}
+
+JNIEXPORT jboolean JNICALL Java_pipe_Pipes_CloseHandle
+(
+ JNIEnv *env,
+ jclass className,
+ jint hNamedPipe
+ )
+{
+ BOOL result;
+ HANDLE pipeHandler = (HANDLE) hNamedPipe;
+ result = CloseHandle(pipeHandler);
+ return result;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_pipe_Pipes_ReadFile
+(
+ JNIEnv *env,
+ jclass className,
+ jint hNamedPipe,
+ jint nNumberOfBytesToRead
+ )
+{
+ int bytesRead = 0;
+ BOOL result;
+ HANDLE pipeHandler = (HANDLE) hNamedPipe;
+ LPVOID buffer;
+ jbyteArray lpBuffer;
+
+ buffer = (LPVOID)LocalAlloc(LMEM_ZEROINIT, nNumberOfBytesToRead);
+
+ if (DEBUG)
+ {
+ printf("Native: Before ReadFile pipeHandler %d nNumberOfBytesToRead %d\n", pipeHandler, nNumberOfBytesToRead);
+ }
+ result = ReadFile(pipeHandler, (LPVOID) buffer, (DWORD) nNumberOfBytesToRead, &bytesRead, (LPOVERLAPPED) 0);
+ if (result)
+ {
+ lpBuffer = (*env)->NewByteArray(env, (jsize) bytesRead);
+ (*env)->SetByteArrayRegion(env, lpBuffer, 0, (jsize) bytesRead, (jbyte *) buffer);
+ } else
+ bytesRead = 0;
+
+ LocalFree(buffer);
+
+ if (DEBUG)
+ {
+ printf("Native: After ReadFile BytesRead %d\n", bytesRead);
+ }
+ return lpBuffer;
+}
+
+JNIEXPORT jint JNICALL Java_pipe_Pipes_WriteFile
+(
+ JNIEnv *env,
+ jclass className,
+ jint hNamedPipe,
+ jbyteArray lpBuffer,
+ jint nNumberOfBytesToWrite
+ )
+{
+ int bytesWritten = 0;
+ BOOL result;
+ HANDLE pipeHandler = (HANDLE) hNamedPipe;
+ LPVOID buffer;
+
+ buffer = (LPVOID)LocalAlloc(LMEM_ZEROINIT, nNumberOfBytesToWrite);
+
+ (*env)->GetByteArrayRegion(env, lpBuffer, 0, nNumberOfBytesToWrite, buffer);
+ result = WriteFile(pipeHandler, buffer, (DWORD) nNumberOfBytesToWrite, (LPDWORD) &bytesWritten, (LPOVERLAPPED) 0);
+ LocalFree(buffer);
+
+ if (DEBUG)
+ {
+ printf("Native: After WriteFile BytesReadWritten %d\n", bytesWritten);
+ }
+
+ if (!result)
+ {
+ if (GetLastError() != ERROR_IO_PENDING)
+ result = 0;
+ else
+ result = 1;
+ }
+ if (!result)
+ {
+ bytesWritten = -1;
+ }
+ return bytesWritten;
+}
+
+JNIEXPORT jboolean JNICALL Java_pipe_Pipes_FlushFileBuffers
+(
+ JNIEnv *env,
+ jclass className,
+ jint hNamedPipe
+ )
+{
+ BOOL result;
+ HANDLE pipeHandler = (HANDLE) hNamedPipe;
+ result = FlushFileBuffers(pipeHandler);
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_pipe_Pipes_DisconnectNamedPipe
+(
+ JNIEnv *env,
+ jclass className,
+ jint hNamedPipe
+ )
+{
+ BOOL result;
+ HANDLE pipeHandler = (HANDLE) hNamedPipe;
+ result = DisconnectNamedPipe(pipeHandler);
+ return result;
+}
+
+JNIEXPORT jint JNICALL Java_pipe_Pipes_CreateFile
+(
+ JNIEnv *env,
+ jclass className,
+ jstring lpFileName,
+ jint dwDesiredAccess,
+ jint dwShareMode,
+ jint lpSecurityAttributes,
+ jint dwCreationDisposition,
+ jint dwFlagsAndAttributes,
+ jint hTemplateFile
+ )
+{
+ HANDLE pipeHandler;
+ const jbyte *fileName;
+ fileName = (*env)->GetStringUTFChars(env, lpFileName, NULL);
+ if (fileName == NULL)
+ return -1;
+ pipeHandler = CreateFile((LPCSTR) fileName, (DWORD) dwDesiredAccess, (DWORD) dwShareMode,
+ (LPSECURITY_ATTRIBUTES) lpSecurityAttributes, (DWORD) dwCreationDisposition, (DWORD) dwFlagsAndAttributes, (HANDLE) hTemplateFile);
+ return (jint) pipeHandler;
+}
+
+JNIEXPORT jboolean JNICALL Java_pipe_Pipes_WaitNamedPipe
+(
+ JNIEnv *env,
+ jclass className,
+ jstring lpNamedPipeName,
+ jint nTimeOut
+ )
+{
+ BOOL result;
+ const jbyte *pipeName;
+ pipeName = (*env)->GetStringUTFChars(env, lpNamedPipeName, NULL);
+ if (pipeName == NULL)
+ return 0;
+ result = WaitNamedPipe((LPCSTR) pipeName, (DWORD) nTimeOut);
+ return result;
+}
+
+JNIEXPORT jstring JNICALL Java_pipe_Pipes_FormatMessage
+(
+ JNIEnv *env,
+ jclass className,
+ jint errorCode
+)
+{
+ LPVOID lpMsgBuf;
+ LPVOID lpDisplayBuf;
+ DWORD dw = (DWORD) errorCode;
+
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ dw,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf,
+ 0, NULL );
+
+ lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
+ (lstrlen((LPCTSTR)lpMsgBuf) + 40) * sizeof(TCHAR));
+ StringCchPrintf((LPTSTR)lpDisplayBuf, LocalSize(lpDisplayBuf) / sizeof(TCHAR),
+ TEXT("Failed with error %d: %s"), dw, lpMsgBuf);
+ return (jstring) (*env)->NewStringUTF(env, lpDisplayBuf);
+}
+
+JNIEXPORT void JNICALL Java_pipe_Pipes_Print(JNIEnv *env, jclass className, jstring lpMsgBuf)
+{
+ const jbyte *str;
+ str = (*env)->GetStringUTFChars(env, lpMsgBuf, NULL);
+ if (str == NULL)
+ return;
+ printf("Native: %s\n", str);
+ (*env)->ReleaseStringUTFChars(env, lpMsgBuf, str);
+ return;
+}
diff --git a/cpp/Pipe/src/pipe.h b/cpp/Pipe/src/pipe.h
new file mode 100644
index 0000000..4687162
--- /dev/null
+++ b/cpp/Pipe/src/pipe.h
@@ -0,0 +1,109 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include
+/* Header for class Pipes */
+
+#ifndef _Included_pipe
+#define _Included_pipe
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: Pipes
+ * Method: CreateNamedPipe
+ * Signature: (Ljava/lang/String;IIIIIII)I
+ */
+JNIEXPORT jint JNICALL Java_pipe_Pipes_CreateNamedPipe
+ (JNIEnv *, jclass, jstring, jint, jint, jint, jint, jint, jint, jint);
+
+/*
+ * Class: Pipes
+ * Method: ConnectNamedPipe
+ * Signature: (II)Z
+ */
+JNIEXPORT jboolean JNICALL Java_pipe_Pipes_ConnectNamedPipe
+ (JNIEnv *, jclass, jint, jint);
+
+/*
+ * Class: Pipes
+ * Method: GetLastError
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_pipe_Pipes_GetLastError
+ (JNIEnv *, jclass);
+
+/*
+ * Class: Pipes
+ * Method: CloseHandle
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_pipe_Pipes_CloseHandle
+ (JNIEnv *, jclass, jint);
+
+/*
+ * Class: Pipes
+ * Method: ReadFile
+ * Signature: (II)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_pipe_Pipes_ReadFile
+ (JNIEnv *, jclass, jint, jint);
+
+/*
+ * Class: Pipes
+ * Method: WriteFile
+ * Signature: (I[BI)I
+ */
+JNIEXPORT jint JNICALL Java_pipe_Pipes_WriteFile
+ (JNIEnv *, jclass, jint, jbyteArray, jint);
+
+/*
+ * Class: Pipes
+ * Method: FlushFileBuffers
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_pipe_Pipes_FlushFileBuffers
+ (JNIEnv *, jclass, jint);
+
+/*
+ * Class: Pipes
+ * Method: DisconnectNamedPipe
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_pipe_Pipes_DisconnectNamedPipe
+ (JNIEnv *, jclass, jint);
+
+/*
+ * Class: Pipes
+ * Method: CreateFile
+ * Signature: (Ljava/lang/String;IIIIII)I
+ */
+JNIEXPORT jint JNICALL Java_pipe_Pipes_CreateFile
+ (JNIEnv *, jclass, jstring, jint, jint, jint, jint, jint, jint);
+
+/*
+ * Class: Pipes
+ * Method: WaitNamedPipe
+ * Signature: (Ljava/lang/String;I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_pipe_Pipes_WaitNamedPipe
+ (JNIEnv *, jclass, jstring, jint);
+
+/*
+ * Class: Pipes
+ * Method: FormatMessage
+ * Signature: (I)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_pipe_Pipes_FormatMessage
+ (JNIEnv *, jclass, jint);
+
+/*
+ * Class: Pipes
+ * Method: Print
+ * Signature: (Ljava/lang/String;)V
+ */
+JNIEXPORT void JNICALL Java_pipe_Pipes_Print
+ (JNIEnv *, jclass, jstring);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/cpp/pipe/.cproject b/cpp/pipe/.cproject
new file mode 100644
index 0000000..7e01e41
--- /dev/null
+++ b/cpp/pipe/.cproject
@@ -0,0 +1,154 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cpp/pipe/.project b/cpp/pipe/.project
new file mode 100644
index 0000000..511c69c
--- /dev/null
+++ b/cpp/pipe/.project
@@ -0,0 +1,27 @@
+
+
+ Pipe
+
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.genmakebuilder
+ clean,full,incremental,
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder
+ full,incremental,
+
+
+
+
+
+ org.eclipse.cdt.core.cnature
+ org.eclipse.cdt.core.ccnature
+ org.eclipse.cdt.managedbuilder.core.managedBuildNature
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigNature
+
+
diff --git a/cpp/pipe/include/strsafe.h b/cpp/pipe/include/strsafe.h
new file mode 100644
index 0000000..061b3c4
--- /dev/null
+++ b/cpp/pipe/include/strsafe.h
@@ -0,0 +1,6611 @@
+/******************************************************************
+* *
+* strsafe.h -- This module defines safer C library string *
+* routine replacements. These are meant to make C *
+* a bit more safe in reference to security and *
+* robustness *
+* *
+* Copyright (c) Microsoft Corp. All rights reserved. *
+* *
+******************************************************************/
+#ifndef _STRSAFE_H_INCLUDED_
+#define _STRSAFE_H_INCLUDED_
+#pragma once
+
+#include // for _vsnprintf, _vsnwprintf, getc, getwc
+#include // for memset
+#include // for va_start, etc.
+
+
+#ifndef _SIZE_T_DEFINED
+#ifdef _WIN64
+typedef unsigned __int64 size_t;
+#else
+typedef __w64 unsigned int size_t;
+#endif // !_WIN64
+#define _SIZE_T_DEFINED
+#endif // !_SIZE_T_DEFINED
+
+#if !defined(_WCHAR_T_DEFINED) && !defined(_NATIVE_WCHAR_T_DEFINED)
+typedef unsigned short wchar_t;
+#define _WCHAR_T_DEFINED
+#endif
+
+#ifndef _HRESULT_DEFINED
+#define _HRESULT_DEFINED
+typedef long HRESULT;
+#endif // !_HRESULT_DEFINED
+
+#ifndef SUCCEEDED
+#define SUCCEEDED(hr) ((HRESULT)(hr) >= 0)
+#endif
+
+#ifndef FAILED
+#define FAILED(hr) ((HRESULT)(hr) < 0)
+#endif
+
+#ifndef S_OK
+#define S_OK ((HRESULT)0x00000000L)
+#endif
+
+#ifdef __cplusplus
+#define _STRSAFE_EXTERN_C extern "C"
+#else
+#define _STRSAFE_EXTERN_C extern
+#endif
+
+// If you do not want to use these functions inline (and instead want to link w/ strsafe.lib), then
+// #define STRSAFE_LIB before including this header file.
+#if defined(STRSAFE_LIB)
+#define STRSAFEAPI _STRSAFE_EXTERN_C HRESULT __stdcall
+#pragma comment(lib, "strsafe.lib")
+#elif defined(STRSAFE_LIB_IMPL)
+#define STRSAFEAPI _STRSAFE_EXTERN_C HRESULT __stdcall
+#else
+#define STRSAFEAPI __inline HRESULT __stdcall
+#define STRSAFE_INLINE
+#endif
+
+// Some functions always run inline because they use stdin and we want to avoid building multiple
+// versions of strsafe lib depending on if you use msvcrt, libcmt, etc.
+#define STRSAFE_INLINE_API __inline HRESULT __stdcall
+
+// The user can request no "Cb" or no "Cch" fuctions, but not both!
+#if defined(STRSAFE_NO_CB_FUNCTIONS) && defined(STRSAFE_NO_CCH_FUNCTIONS)
+#error cannot specify both STRSAFE_NO_CB_FUNCTIONS and STRSAFE_NO_CCH_FUNCTIONS !!
+#endif
+
+// This should only be defined when we are building strsafe.lib
+#ifdef STRSAFE_LIB_IMPL
+#define STRSAFE_INLINE
+#endif
+
+
+// If both strsafe.h and ntstrsafe.h are included, only use definitions from one.
+#ifndef _NTSTRSAFE_H_INCLUDED_
+
+#define STRSAFE_MAX_CCH 2147483647 // max # of characters we support (same as INT_MAX)
+
+// Flags for controling the Ex functions
+//
+// STRSAFE_FILL_BYTE(0xFF) 0x000000FF // bottom byte specifies fill pattern
+#define STRSAFE_IGNORE_NULLS 0x00000100 // treat null as TEXT("") -- don't fault on NULL buffers
+#define STRSAFE_FILL_BEHIND_NULL 0x00000200 // fill in extra space behind the null terminator
+#define STRSAFE_FILL_ON_FAILURE 0x00000400 // on failure, overwrite pszDest with fill pattern and null terminate it
+#define STRSAFE_NULL_ON_FAILURE 0x00000800 // on failure, set *pszDest = TEXT('\0')
+#define STRSAFE_NO_TRUNCATION 0x00001000 // instead of returning a truncated result, copy/append nothing to pszDest and null terminate it
+
+#define STRSAFE_VALID_FLAGS (0x000000FF | STRSAFE_IGNORE_NULLS | STRSAFE_FILL_BEHIND_NULL | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION)
+
+// helper macro to set the fill character and specify buffer filling
+#define STRSAFE_FILL_BYTE(x) ((unsigned long)((x & 0x000000FF) | STRSAFE_FILL_BEHIND_NULL))
+#define STRSAFE_FAILURE_BYTE(x) ((unsigned long)((x & 0x000000FF) | STRSAFE_FILL_ON_FAILURE))
+
+#define STRSAFE_GET_FILL_PATTERN(dwFlags) ((int)(dwFlags & 0x000000FF))
+
+#endif // _NTSTRSAFE_H_INCLUDED_
+
+// STRSAFE error return codes
+//
+#define STRSAFE_E_INSUFFICIENT_BUFFER ((HRESULT)0x8007007AL) // 0x7A = 122L = ERROR_INSUFFICIENT_BUFFER
+#define STRSAFE_E_INVALID_PARAMETER ((HRESULT)0x80070057L) // 0x57 = 87L = ERROR_INVALID_PARAMETER
+#define STRSAFE_E_END_OF_FILE ((HRESULT)0x80070026L) // 0x26 = 38L = ERROR_HANDLE_EOF
+
+// prototypes for the worker functions
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCopyWorkerA(char* pszDest, size_t cchDest, const char* pszSrc);
+STRSAFEAPI StringCopyWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc);
+STRSAFEAPI StringCopyExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCopyExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCopyNWorkerA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc);
+STRSAFEAPI StringCopyNWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc);
+STRSAFEAPI StringCopyNExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, size_t cchSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCopyNExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, size_t cchSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCatWorkerA(char* pszDest, size_t cchDest, const char* pszSrc);
+STRSAFEAPI StringCatWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc);
+STRSAFEAPI StringCatExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCatExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCatNWorkerA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend);
+STRSAFEAPI StringCatNWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend);
+STRSAFEAPI StringCatNExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, size_t cchMaxAppend, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCatNExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, size_t cchMaxAppend, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringVPrintfWorkerA(char* pszDest, size_t cchDest, const char* pszFormat, va_list argList);
+STRSAFEAPI StringVPrintfWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, va_list argList);
+STRSAFEAPI StringVPrintfExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList);
+STRSAFEAPI StringVPrintfExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList);
+STRSAFEAPI StringLengthWorkerA(const char* psz, size_t cchMax, size_t* pcch);
+STRSAFEAPI StringLengthWorkerW(const wchar_t* psz, size_t cchMax, size_t* pcch);
+#endif // STRSAFE_INLINE
+
+#ifndef STRSAFE_LIB_IMPL
+// these functions are always inline
+STRSAFE_INLINE_API StringGetsExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFE_INLINE_API StringGetsExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+#endif
+
+#ifdef _NTSTRSAFE_H_INCLUDED_
+#pragma warning(push)
+#pragma warning(disable : 4995)
+#endif // _NTSTRSAFE_H_INCLUDED_
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI
+StringCchCopy(
+ OUT LPTSTR pszDest,
+ IN size_t cchDest,
+ IN LPCTSTR pszSrc
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strcpy'.
+ The size of the destination buffer (in characters) is a parameter and
+ this function will not write past the end of this buffer and it will
+ ALWAYS null terminate the destination buffer (unless it is zero length).
+
+ This routine is not a replacement for strncpy. That function will pad the
+ destination string with extra null termination characters if the count is
+ greater than the length of the source string, and it will fail to null
+ terminate the destination string if the source string length is greater
+ than or equal to the count. You can not blindly use this instead of strncpy:
+ it is common for code to use it to "patch" strings and you would introduce
+ errors if the code started null terminating in the middle of the string.
+
+ This function returns a hresult, and not a pointer. It returns
+ S_OK if the string was copied without truncation and null terminated,
+ otherwise it will return a failure code. In failure cases as much of
+ pszSrc will be copied to pszDest as possible, and pszDest will be null
+ terminated.
+
+Arguments:
+
+ pszDest - destination string
+
+ cchDest - size of destination buffer in characters.
+ length must be = (_tcslen(src) + 1) to hold all of the
+ source including the null terminator
+
+ pszSrc - source string which must be null terminated
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL. See StringCchCopyEx if you require
+ the handling of NULL values.
+
+Return Value:
+
+ S_OK - if there was source data and it was all copied and the
+ resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the copy
+ operation failed due to insufficient space. When this
+ error occurs, the destination buffer is modified to
+ contain a truncated version of the ideal result and is
+ null terminated. This is useful for situations where
+ truncation is ok
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function.
+
+--*/
+
+STRSAFEAPI StringCchCopyA(char* pszDest, size_t cchDest, const char* pszSrc);
+STRSAFEAPI StringCchCopyW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc);
+#ifdef UNICODE
+#define StringCchCopy StringCchCopyW
+#else
+#define StringCchCopy StringCchCopyA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchCopyA(char* pszDest, size_t cchDest, const char* pszSrc)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyWorkerA(pszDest, cchDest, pszSrc);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCchCopyW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyWorkerW(pszDest, cchDest, pszSrc);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI
+StringCbCopy(
+ OUT LPTSTR pszDest,
+ IN size_t cbDest,
+ IN LPCTSTR pszSrc
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strcpy'.
+ The size of the destination buffer (in bytes) is a parameter and this
+ function will not write past the end of this buffer and it will ALWAYS
+ null terminate the destination buffer (unless it is zero length).
+
+ This routine is not a replacement for strncpy. That function will pad the
+ destination string with extra null termination characters if the count is
+ greater than the length of the source string, and it will fail to null
+ terminate the destination string if the source string length is greater
+ than or equal to the count. You can not blindly use this instead of strncpy:
+ it is common for code to use it to "patch" strings and you would introduce
+ errors if the code started null terminating in the middle of the string.
+
+ This function returns a hresult, and not a pointer. It returns
+ S_OK if the string was copied without truncation and null terminated,
+ otherwise it will return a failure code. In failure cases as much of pszSrc
+ will be copied to pszDest as possible, and pszDest will be null terminated.
+
+Arguments:
+
+ pszDest - destination string
+
+ cbDest - size of destination buffer in bytes.
+ length must be = ((_tcslen(src) + 1) * sizeof(TCHAR)) to
+ hold all of the source including the null terminator
+
+ pszSrc - source string which must be null terminated
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL. See StringCbCopyEx if you require
+ the handling of NULL values.
+
+Return Value:
+
+ S_OK - if there was source data and it was all copied and the
+ resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the copy
+ operation failed due to insufficient space. When this
+ error occurs, the destination buffer is modified to
+ contain a truncated version of the ideal result and is
+ null terminated. This is useful for situations where
+ truncation is ok
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function.
+
+--*/
+
+STRSAFEAPI StringCbCopyA(char* pszDest, size_t cbDest, const char* pszSrc);
+STRSAFEAPI StringCbCopyW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc);
+#ifdef UNICODE
+#define StringCbCopy StringCbCopyW
+#else
+#define StringCbCopy StringCbCopyA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbCopyA(char* pszDest, size_t cbDest, const char* pszSrc)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ // convert to count of characters
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyWorkerA(pszDest, cchDest, pszSrc);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCbCopyW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ // convert to count of characters
+ cchDest = cbDest / sizeof(wchar_t);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyWorkerW(pszDest, cchDest, pszSrc);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI
+StringCchCopyEx(
+ OUT LPTSTR pszDest OPTIONAL,
+ IN size_t cchDest,
+ IN LPCTSTR pszSrc OPTIONAL,
+ OUT LPTSTR* ppszDestEnd OPTIONAL,
+ OUT size_t* pcchRemaining OPTIONAL,
+ IN DWORD dwFlags
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strcpy' with
+ some additional parameters. In addition to functionality provided by
+ StringCchCopy, this routine also returns a pointer to the end of the
+ destination string and the number of characters left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string
+
+ cchDest - size of destination buffer in characters.
+ length must be = (_tcslen(pszSrc) + 1) to hold all of
+ the source including the null terminator
+
+ pszSrc - source string which must be null terminated
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function copied any data, the result will point to the
+ null termination character
+
+ pcchRemaining - if pcchRemaining is non-null, the function will return the
+ number of characters left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT("")).
+ this flag is useful for emulating functions like lstrcpy
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any truncated
+ string returned when the failure is
+ STRSAFE_E_INSUFFICIENT_BUFFER
+
+ STRSAFE_NO_TRUNCATION /
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any truncated string
+ returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
+ is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
+ may be NULL. An error may still be returned even though NULLS are ignored
+ due to insufficient space.
+
+Return Value:
+
+ S_OK - if there was source data and it was all copied and the
+ resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the copy
+ operation failed due to insufficient space. When this
+ error occurs, the destination buffer is modified to
+ contain a truncated version of the ideal result and is
+ null terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCchCopyExA(char* pszDest, size_t cchDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCchCopyExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+#ifdef UNICODE
+#define StringCchCopyEx StringCchCopyExW
+#else
+#define StringCchCopyEx StringCchCopyExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchCopyExA(char* pszDest, size_t cchDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
+ cbDest = cchDest * sizeof(char);
+
+ hr = StringCopyExWorkerA(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCchCopyExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
+ cbDest = cchDest * sizeof(wchar_t);
+
+ hr = StringCopyExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI
+StringCbCopyEx(
+ OUT LPTSTR pszDest OPTIONAL,
+ IN size_t cbDest,
+ IN LPCTSTR pszSrc OPTIONAL,
+ OUT LPTSTR* ppszDestEnd OPTIONAL,
+ OUT size_t* pcbRemaining OPTIONAL,
+ IN DWORD dwFlags
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strcpy' with
+ some additional parameters. In addition to functionality provided by
+ StringCbCopy, this routine also returns a pointer to the end of the
+ destination string and the number of bytes left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string
+
+ cbDest - size of destination buffer in bytes.
+ length must be ((_tcslen(pszSrc) + 1) * sizeof(TCHAR)) to
+ hold all of the source including the null terminator
+
+ pszSrc - source string which must be null terminated
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function copied any data, the result will point to the
+ null termination character
+
+ pcbRemaining - pcbRemaining is non-null,the function will return the
+ number of bytes left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT("")).
+ this flag is useful for emulating functions like lstrcpy
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any truncated
+ string returned when the failure is
+ STRSAFE_E_INSUFFICIENT_BUFFER
+
+ STRSAFE_NO_TRUNCATION /
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any truncated string
+ returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
+ is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
+ may be NULL. An error may still be returned even though NULLS are ignored
+ due to insufficient space.
+
+Return Value:
+
+ S_OK - if there was source data and it was all copied and the
+ resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the copy
+ operation failed due to insufficient space. When this
+ error occurs, the destination buffer is modified to
+ contain a truncated version of the ideal result and is
+ null terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCbCopyExA(char* pszDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCbCopyExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
+#ifdef UNICODE
+#define StringCbCopyEx StringCbCopyExW
+#else
+#define StringCbCopyEx StringCbCopyExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbCopyExA(char* pszDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyExWorkerA(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
+ *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCbCopyExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(wchar_t);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
+ *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
+ }
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI
+StringCchCopyN(
+ OUT LPTSTR pszDest,
+ IN size_t cchDest,
+ IN LPCTSTR pszSrc,
+ IN size_t cchSrc
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strncpy'.
+ The size of the destination buffer (in characters) is a parameter and
+ this function will not write past the end of this buffer and it will
+ ALWAYS null terminate the destination buffer (unless it is zero length).
+
+ This routine is meant as a replacement for strncpy, but it does behave
+ differently. This function will not pad the destination buffer with extra
+ null termination characters if cchSrc is greater than the length of pszSrc.
+
+ This function returns a hresult, and not a pointer. It returns
+ S_OK if the entire string or the first cchSrc characters were copied
+ without truncation and the resultant destination string was null terminated,
+ otherwise it will return a failure code. In failure cases as much of pszSrc
+ will be copied to pszDest as possible, and pszDest will be null terminated.
+
+Arguments:
+
+ pszDest - destination string
+
+ cchDest - size of destination buffer in characters.
+ length must be = (_tcslen(src) + 1) to hold all of the
+ source including the null terminator
+
+ pszSrc - source string
+
+ cchSrc - maximum number of characters to copy from source string,
+ not including the null terminator.
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL. See StringCchCopyNEx if you require
+ the handling of NULL values.
+
+Return Value:
+
+ S_OK - if there was source data and it was all copied and the
+ resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the copy
+ operation failed due to insufficient space. When this
+ error occurs, the destination buffer is modified to
+ contain a truncated version of the ideal result and is
+ null terminated. This is useful for situations where
+ truncation is ok
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function.
+
+--*/
+
+STRSAFEAPI StringCchCopyNA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc);
+STRSAFEAPI StringCchCopyNW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc);
+#ifdef UNICODE
+#define StringCchCopyN StringCchCopyNW
+#else
+#define StringCchCopyN StringCchCopyNA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchCopyNA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc)
+{
+ HRESULT hr;
+
+ if ((cchDest > STRSAFE_MAX_CCH) ||
+ (cchSrc > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyNWorkerA(pszDest, cchDest, pszSrc, cchSrc);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCchCopyNW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc)
+{
+ HRESULT hr;
+
+ if ((cchDest > STRSAFE_MAX_CCH) ||
+ (cchSrc > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyNWorkerW(pszDest, cchDest, pszSrc, cchSrc);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI
+StringCbCopyN(
+ OUT LPTSTR pszDest,
+ IN size_t cbDest,
+ IN LPCTSTR pszSrc,
+ IN size_t cbSrc
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strncpy'.
+ The size of the destination buffer (in bytes) is a parameter and this
+ function will not write past the end of this buffer and it will ALWAYS
+ null terminate the destination buffer (unless it is zero length).
+
+ This routine is meant as a replacement for strncpy, but it does behave
+ differently. This function will not pad the destination buffer with extra
+ null termination characters if cbSrc is greater than the size of pszSrc.
+
+ This function returns a hresult, and not a pointer. It returns
+ S_OK if the entire string or the first cbSrc characters were
+ copied without truncation and the resultant destination string was null
+ terminated, otherwise it will return a failure code. In failure cases as
+ much of pszSrc will be copied to pszDest as possible, and pszDest will be
+ null terminated.
+
+Arguments:
+
+ pszDest - destination string
+
+ cbDest - size of destination buffer in bytes.
+ length must be = ((_tcslen(src) + 1) * sizeof(TCHAR)) to
+ hold all of the source including the null terminator
+
+ pszSrc - source string
+
+ cbSrc - maximum number of bytes to copy from source string,
+ not including the null terminator.
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL. See StringCbCopyEx if you require
+ the handling of NULL values.
+
+Return Value:
+
+ S_OK - if there was source data and it was all copied and the
+ resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the copy
+ operation failed due to insufficient space. When this
+ error occurs, the destination buffer is modified to
+ contain a truncated version of the ideal result and is
+ null terminated. This is useful for situations where
+ truncation is ok
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function.
+
+--*/
+
+STRSAFEAPI StringCbCopyNA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbSrc);
+STRSAFEAPI StringCbCopyNW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbSrc);
+#ifdef UNICODE
+#define StringCbCopyN StringCbCopyNW
+#else
+#define StringCbCopyN StringCbCopyNA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbCopyNA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbSrc)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchSrc;
+
+ // convert to count of characters
+ cchDest = cbDest / sizeof(char);
+ cchSrc = cbSrc / sizeof(char);
+
+ if ((cchDest > STRSAFE_MAX_CCH) ||
+ (cchSrc > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyNWorkerA(pszDest, cchDest, pszSrc, cchSrc);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCbCopyNW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbSrc)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchSrc;
+
+ // convert to count of characters
+ cchDest = cbDest / sizeof(wchar_t);
+ cchSrc = cbSrc / sizeof(wchar_t);
+
+ if ((cchDest > STRSAFE_MAX_CCH) ||
+ (cchSrc > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyNWorkerW(pszDest, cchDest, pszSrc, cchSrc);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI
+StringCchCopyNEx(
+ OUT LPTSTR pszDest OPTIONAL,
+ IN size_t cchDest,
+ IN LPCTSTR pszSrc OPTIONAL,
+ IN size_t cchSrc,
+ OUT LPTSTR* ppszDestEnd OPTIONAL,
+ OUT size_t* pcchRemaining OPTIONAL,
+ IN DWORD dwFlags
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strncpy' with
+ some additional parameters. In addition to functionality provided by
+ StringCchCopyN, this routine also returns a pointer to the end of the
+ destination string and the number of characters left in the destination
+ string including the null terminator. The flags parameter allows
+ additional controls.
+
+ This routine is meant as a replacement for strncpy, but it does behave
+ differently. This function will not pad the destination buffer with extra
+ null termination characters if cchSrc is greater than the length of pszSrc.
+
+Arguments:
+
+ pszDest - destination string
+
+ cchDest - size of destination buffer in characters.
+ length must be = (_tcslen(pszSrc) + 1) to hold all of
+ the source including the null terminator
+
+ pszSrc - source string
+
+ cchSrc - maximum number of characters to copy from the source
+ string
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function copied any data, the result will point to the
+ null termination character
+
+ pcchRemaining - if pcchRemaining is non-null, the function will return the
+ number of characters left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT("")).
+ this flag is useful for emulating functions like lstrcpy
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any truncated
+ string returned when the failure is
+ STRSAFE_E_INSUFFICIENT_BUFFER
+
+ STRSAFE_NO_TRUNCATION /
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any truncated string
+ returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
+ is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
+ may be NULL. An error may still be returned even though NULLS are ignored
+ due to insufficient space.
+
+Return Value:
+
+ S_OK - if there was source data and it was all copied and the
+ resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the copy
+ operation failed due to insufficient space. When this
+ error occurs, the destination buffer is modified to
+ contain a truncated version of the ideal result and is
+ null terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCchCopyNExA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCchCopyNExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+#ifdef UNICODE
+#define StringCchCopyNEx StringCchCopyNExW
+#else
+#define StringCchCopyNEx StringCchCopyNExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchCopyNExA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+
+ if ((cchDest > STRSAFE_MAX_CCH) ||
+ (cchSrc > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
+ cbDest = cchDest * sizeof(char);
+
+ hr = StringCopyNExWorkerA(pszDest, cchDest, cbDest, pszSrc, cchSrc, ppszDestEnd, pcchRemaining, dwFlags);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCchCopyNExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+
+ if ((cchDest > STRSAFE_MAX_CCH) ||
+ (cchSrc > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
+ cbDest = cchDest * sizeof(wchar_t);
+
+ hr = StringCopyNExWorkerW(pszDest, cchDest, cbDest, pszSrc, cchSrc, ppszDestEnd, pcchRemaining, dwFlags);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI
+StringCbCopyNEx(
+ OUT LPTSTR pszDest OPTIONAL,
+ IN size_t cbDest,
+ IN LPCTSTR pszSrc OPTIONAL,
+ IN size_t cbSrc,
+ OUT LPTSTR* ppszDestEnd OPTIONAL,
+ OUT size_t* pcbRemaining OPTIONAL,
+ IN DWORD dwFlags
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strncpy' with
+ some additional parameters. In addition to functionality provided by
+ StringCbCopyN, this routine also returns a pointer to the end of the
+ destination string and the number of bytes left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+ This routine is meant as a replacement for strncpy, but it does behave
+ differently. This function will not pad the destination buffer with extra
+ null termination characters if cbSrc is greater than the size of pszSrc.
+
+Arguments:
+
+ pszDest - destination string
+
+ cbDest - size of destination buffer in bytes.
+ length must be ((_tcslen(pszSrc) + 1) * sizeof(TCHAR)) to
+ hold all of the source including the null terminator
+
+ pszSrc - source string
+
+ cbSrc - maximum number of bytes to copy from source string
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function copied any data, the result will point to the
+ null termination character
+
+ pcbRemaining - pcbRemaining is non-null,the function will return the
+ number of bytes left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT("")).
+ this flag is useful for emulating functions like lstrcpy
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any truncated
+ string returned when the failure is
+ STRSAFE_E_INSUFFICIENT_BUFFER
+
+ STRSAFE_NO_TRUNCATION /
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any truncated string
+ returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
+ is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
+ may be NULL. An error may still be returned even though NULLS are ignored
+ due to insufficient space.
+
+Return Value:
+
+ S_OK - if there was source data and it was all copied and the
+ resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the copy
+ operation failed due to insufficient space. When this
+ error occurs, the destination buffer is modified to
+ contain a truncated version of the ideal result and is
+ null terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCbCopyNExA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCbCopyNExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
+#ifdef UNICODE
+#define StringCbCopyNEx StringCbCopyNExW
+#else
+#define StringCbCopyNEx StringCbCopyNExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbCopyNExA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchSrc;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(char);
+ cchSrc = cbSrc / sizeof(char);
+
+ if ((cchDest > STRSAFE_MAX_CCH) ||
+ (cchSrc > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyNExWorkerA(pszDest, cchDest, cbDest, pszSrc, cchSrc, ppszDestEnd, &cchRemaining, dwFlags);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
+ *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCbCopyNExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchSrc;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(wchar_t);
+ cchSrc = cbSrc / sizeof(wchar_t);
+
+ if ((cchDest > STRSAFE_MAX_CCH) ||
+ (cchSrc > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyNExWorkerW(pszDest, cchDest, cbDest, pszSrc, cchSrc, ppszDestEnd, &cchRemaining, dwFlags);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
+ *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
+ }
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI
+StringCchCat(
+ IN OUT LPTSTR pszDest,
+ IN size_t cchDest,
+ IN LPCTSTR pszSrc
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strcat'.
+ The size of the destination buffer (in characters) is a parameter and this
+ function will not write past the end of this buffer and it will ALWAYS
+ null terminate the destination buffer (unless it is zero length).
+
+ This function returns a hresult, and not a pointer. It returns
+ S_OK if the string was concatenated without truncation and null terminated,
+ otherwise it will return a failure code. In failure cases as much of pszSrc
+ will be appended to pszDest as possible, and pszDest will be null
+ terminated.
+
+Arguments:
+
+ pszDest - destination string which must be null terminated
+
+ cchDest - size of destination buffer in characters.
+ length must be = (_tcslen(pszDest) + _tcslen(pszSrc) + 1)
+ to hold all of the combine string plus the null
+ terminator
+
+ pszSrc - source string which must be null terminated
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL. See StringCchCatEx if you require
+ the handling of NULL values.
+
+Return Value:
+
+ S_OK - if there was source data and it was all concatenated and
+ the resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the operation
+ failed due to insufficient space. When this error occurs,
+ the destination buffer is modified to contain a truncated
+ version of the ideal result and is null terminated. This
+ is useful for situations where truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCchCatA(char* pszDest, size_t cchDest, const char* pszSrc);
+STRSAFEAPI StringCchCatW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc);
+#ifdef UNICODE
+#define StringCchCat StringCchCatW
+#else
+#define StringCchCat StringCchCatA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchCatA(char* pszDest, size_t cchDest, const char* pszSrc)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCatWorkerA(pszDest, cchDest, pszSrc);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCchCatW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCatWorkerW(pszDest, cchDest, pszSrc);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI
+StringCbCat(
+ IN OUT LPTSTR pszDest,
+ IN size_t cbDest,
+ IN LPCTSTR pszSrc
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strcat'.
+ The size of the destination buffer (in bytes) is a parameter and this
+ function will not write past the end of this buffer and it will ALWAYS
+ null terminate the destination buffer (unless it is zero length).
+
+ This function returns a hresult, and not a pointer. It returns
+ S_OK if the string was concatenated without truncation and null terminated,
+ otherwise it will return a failure code. In failure cases as much of pszSrc
+ will be appended to pszDest as possible, and pszDest will be null
+ terminated.
+
+Arguments:
+
+ pszDest - destination string which must be null terminated
+
+ cbDest - size of destination buffer in bytes.
+ length must be = ((_tcslen(pszDest) + _tcslen(pszSrc) + 1) * sizeof(TCHAR)
+ to hold all of the combine string plus the null
+ terminator
+
+ pszSrc - source string which must be null terminated
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL. See StringCbCatEx if you require
+ the handling of NULL values.
+
+Return Value:
+
+ S_OK - if there was source data and it was all concatenated and
+ the resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the operation
+ failed due to insufficient space. When this error occurs,
+ the destination buffer is modified to contain a truncated
+ version of the ideal result and is null terminated. This
+ is useful for situations where truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCbCatA(char* pszDest, size_t cbDest, const char* pszSrc);
+STRSAFEAPI StringCbCatW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc);
+#ifdef UNICODE
+#define StringCbCat StringCbCatW
+#else
+#define StringCbCat StringCbCatA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbCatA(char* pszDest, size_t cbDest, const char* pszSrc)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCatWorkerA(pszDest, cchDest, pszSrc);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCbCatW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ cchDest = cbDest / sizeof(wchar_t);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCatWorkerW(pszDest, cchDest, pszSrc);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI
+StringCchCatEx(
+ IN OUT LPTSTR pszDest OPTIONAL,
+ IN size_t cchDest,
+ IN LPCTSTR pszSrc OPTIONAL,
+ OUT LPTSTR* ppszDestEnd OPTIONAL,
+ OUT size_t* pcchRemaining OPTIONAL,
+ IN DWORD dwFlags
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strcat' with
+ some additional parameters. In addition to functionality provided by
+ StringCchCat, this routine also returns a pointer to the end of the
+ destination string and the number of characters left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string which must be null terminated
+
+ cchDest - size of destination buffer in characters
+ length must be (_tcslen(pszDest) + _tcslen(pszSrc) + 1)
+ to hold all of the combine string plus the null
+ terminator.
+
+ pszSrc - source string which must be null terminated
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function appended any data, the result will point to the
+ null termination character
+
+ pcchRemaining - if pcchRemaining is non-null, the function will return the
+ number of characters left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT("")).
+ this flag is useful for emulating functions like lstrcat
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any pre-existing
+ or truncated string
+
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any pre-existing or
+ truncated string
+
+ STRSAFE_NO_TRUNCATION
+ if the function returns STRSAFE_E_INSUFFICIENT_BUFFER, pszDest
+ will not contain a truncated string, it will remain unchanged.
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
+ is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
+ may be NULL. An error may still be returned even though NULLS are ignored
+ due to insufficient space.
+
+Return Value:
+
+ S_OK - if there was source data and it was all concatenated and
+ the resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the operation
+ failed due to insufficient space. When this error
+ occurs, the destination buffer is modified to contain
+ a truncated version of the ideal result and is null
+ terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCchCatExA(char* pszDest, size_t cchDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCchCatExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+#ifdef UNICODE
+#define StringCchCatEx StringCchCatExW
+#else
+#define StringCchCatEx StringCchCatExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchCatExA(char* pszDest, size_t cchDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
+ cbDest = cchDest * sizeof(char);
+
+ hr = StringCatExWorkerA(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCchCatExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
+ cbDest = cchDest * sizeof(wchar_t);
+
+ hr = StringCatExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI
+StringCbCatEx(
+ IN OUT LPTSTR pszDest OPTIONAL,
+ IN size_t cbDest,
+ IN LPCTSTR pszSrc OPTIONAL,
+ OUT LPTSTR* ppszDestEnd OPTIONAL,
+ OUT size_t* pcbRemaining OPTIONAL,
+ IN DWORD dwFlags
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strcat' with
+ some additional parameters. In addition to functionality provided by
+ StringCbCat, this routine also returns a pointer to the end of the
+ destination string and the number of bytes left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string which must be null terminated
+
+ cbDest - size of destination buffer in bytes.
+ length must be ((_tcslen(pszDest) + _tcslen(pszSrc) + 1) * sizeof(TCHAR)
+ to hold all of the combine string plus the null
+ terminator.
+
+ pszSrc - source string which must be null terminated
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function appended any data, the result will point to the
+ null termination character
+
+ pcbRemaining - if pcbRemaining is non-null, the function will return
+ the number of bytes left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT("")).
+ this flag is useful for emulating functions like lstrcat
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any pre-existing
+ or truncated string
+
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any pre-existing or
+ truncated string
+
+ STRSAFE_NO_TRUNCATION
+ if the function returns STRSAFE_E_INSUFFICIENT_BUFFER, pszDest
+ will not contain a truncated string, it will remain unchanged.
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
+ is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
+ may be NULL. An error may still be returned even though NULLS are ignored
+ due to insufficient space.
+
+Return Value:
+
+ S_OK - if there was source data and it was all concatenated
+ and the resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the operation
+ failed due to insufficient space. When this error
+ occurs, the destination buffer is modified to contain
+ a truncated version of the ideal result and is null
+ terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCbCatExA(char* pszDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCbCatExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
+#ifdef UNICODE
+#define StringCbCatEx StringCbCatExW
+#else
+#define StringCbCatEx StringCbCatExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbCatExA(char* pszDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCatExWorkerA(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
+ *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCbCatExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(wchar_t);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCatExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
+ *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
+ }
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI
+StringCchCatN(
+ IN OUT LPTSTR pszDest,
+ IN size_t cchDest,
+ IN LPCTSTR pszSrc,
+ IN size_t cchMaxAppend
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strncat'.
+ The size of the destination buffer (in characters) is a parameter as well as
+ the maximum number of characters to append, excluding the null terminator.
+ This function will not write past the end of the destination buffer and it will
+ ALWAYS null terminate pszDest (unless it is zero length).
+
+ This function returns a hresult, and not a pointer. It returns
+ S_OK if all of pszSrc or the first cchMaxAppend characters were appended
+ to the destination string and it was null terminated, otherwise it will
+ return a failure code. In failure cases as much of pszSrc will be appended
+ to pszDest as possible, and pszDest will be null terminated.
+
+Arguments:
+
+ pszDest - destination string which must be null terminated
+
+ cchDest - size of destination buffer in characters.
+ length must be (_tcslen(pszDest) + min(cchMaxAppend, _tcslen(pszSrc)) + 1)
+ to hold all of the combine string plus the null
+ terminator.
+
+ pszSrc - source string
+
+ cchMaxAppend - maximum number of characters to append
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL. See StringCchCatNEx if you require
+ the handling of NULL values.
+
+Return Value:
+
+ S_OK - if all of pszSrc or the first cchMaxAppend characters
+ were concatenated to pszDest and the resultant dest
+ string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the operation
+ failed due to insufficient space. When this error
+ occurs, the destination buffer is modified to contain
+ a truncated version of the ideal result and is null
+ terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCchCatNA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend);
+STRSAFEAPI StringCchCatNW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend);
+#ifdef UNICODE
+#define StringCchCatN StringCchCatNW
+#else
+#define StringCchCatN StringCchCatNA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchCatNA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCatNWorkerA(pszDest, cchDest, pszSrc, cchMaxAppend);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCchCatNW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCatNWorkerW(pszDest, cchDest, pszSrc, cchMaxAppend);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI
+StringCbCatN(
+ IN OUT LPTSTR pszDest,
+ IN size_t cbDest,
+ IN LPCTSTR pszSrc,
+ IN size_t cbMaxAppend
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strncat'.
+ The size of the destination buffer (in bytes) is a parameter as well as
+ the maximum number of bytes to append, excluding the null terminator.
+ This function will not write past the end of the destination buffer and it will
+ ALWAYS null terminate pszDest (unless it is zero length).
+
+ This function returns a hresult, and not a pointer. It returns
+ S_OK if all of pszSrc or the first cbMaxAppend bytes were appended
+ to the destination string and it was null terminated, otherwise it will
+ return a failure code. In failure cases as much of pszSrc will be appended
+ to pszDest as possible, and pszDest will be null terminated.
+
+Arguments:
+
+ pszDest - destination string which must be null terminated
+
+ cbDest - size of destination buffer in bytes.
+ length must be ((_tcslen(pszDest) + min(cbMaxAppend / sizeof(TCHAR), _tcslen(pszSrc)) + 1) * sizeof(TCHAR)
+ to hold all of the combine string plus the null
+ terminator.
+
+ pszSrc - source string
+
+ cbMaxAppend - maximum number of bytes to append
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL. See StringCbCatNEx if you require
+ the handling of NULL values.
+
+Return Value:
+
+ S_OK - if all of pszSrc or the first cbMaxAppend bytes were
+ concatenated to pszDest and the resultant dest string
+ was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the operation
+ failed due to insufficient space. When this error
+ occurs, the destination buffer is modified to contain
+ a truncated version of the ideal result and is null
+ terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCbCatNA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbMaxAppend);
+STRSAFEAPI StringCbCatNW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbMaxAppend);
+#ifdef UNICODE
+#define StringCbCatN StringCbCatNW
+#else
+#define StringCbCatN StringCbCatNA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbCatNA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbMaxAppend)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cchMaxAppend;
+
+ cchMaxAppend = cbMaxAppend / sizeof(char);
+
+ hr = StringCatNWorkerA(pszDest, cchDest, pszSrc, cchMaxAppend);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCbCatNW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbMaxAppend)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ cchDest = cbDest / sizeof(wchar_t);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cchMaxAppend;
+
+ cchMaxAppend = cbMaxAppend / sizeof(wchar_t);
+
+ hr = StringCatNWorkerW(pszDest, cchDest, pszSrc, cchMaxAppend);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI
+StringCchCatNEx(
+ IN OUT LPTSTR pszDest OPTIONAL,
+ IN size_t cchDest,
+ IN LPCTSTR pszSrc OPTIONAL,
+ IN size_t cchMaxAppend,
+ OUT LPTSTR* ppszDestEnd OPTIONAL,
+ OUT size_t* pcchRemaining OPTIONAL,
+ IN DWORD dwFlags
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strncat', with
+ some additional parameters. In addition to functionality provided by
+ StringCchCatN, this routine also returns a pointer to the end of the
+ destination string and the number of characters left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string which must be null terminated
+
+ cchDest - size of destination buffer in characters.
+ length must be (_tcslen(pszDest) + min(cchMaxAppend, _tcslen(pszSrc)) + 1)
+ to hold all of the combine string plus the null
+ terminator.
+
+ pszSrc - source string
+
+ cchMaxAppend - maximum number of characters to append
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function appended any data, the result will point to the
+ null termination character
+
+ pcchRemaining - if pcchRemaining is non-null, the function will return the
+ number of characters left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT(""))
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any pre-existing
+ or truncated string
+
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any pre-existing or
+ truncated string
+
+ STRSAFE_NO_TRUNCATION
+ if the function returns STRSAFE_E_INSUFFICIENT_BUFFER, pszDest
+ will not contain a truncated string, it will remain unchanged.
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
+ is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
+ may be NULL. An error may still be returned even though NULLS are ignored
+ due to insufficient space.
+
+Return Value:
+
+ S_OK - if all of pszSrc or the first cchMaxAppend characters
+ were concatenated to pszDest and the resultant dest
+ string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the operation
+ failed due to insufficient space. When this error
+ occurs, the destination buffer is modified to contain
+ a truncated version of the ideal result and is null
+ terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCchCatNExA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCchCatNExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+#ifdef UNICODE
+#define StringCchCatNEx StringCchCatNExW
+#else
+#define StringCchCatNEx StringCchCatNExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchCatNExA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
+ cbDest = cchDest * sizeof(char);
+
+ hr = StringCatNExWorkerA(pszDest, cchDest, cbDest, pszSrc, cchMaxAppend, ppszDestEnd, pcchRemaining, dwFlags);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCchCatNExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
+ cbDest = cchDest * sizeof(wchar_t);
+
+ hr = StringCatNExWorkerW(pszDest, cchDest, cbDest, pszSrc, cchMaxAppend, ppszDestEnd, pcchRemaining, dwFlags);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI
+StringCbCatNEx(
+ IN OUT LPTSTR pszDest OPTIONAL,
+ IN size_t cbDest,
+ IN LPCTSTR pszSrc OPTIONAL,
+ IN size_t cbMaxAppend,
+ OUT LPTSTR* ppszDestEnd OPTIONAL,
+ OUT size_t* pcchRemaining OPTIONAL,
+ IN DWORD dwFlags
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strncat', with
+ some additional parameters. In addition to functionality provided by
+ StringCbCatN, this routine also returns a pointer to the end of the
+ destination string and the number of bytes left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string which must be null terminated
+
+ cbDest - size of destination buffer in bytes.
+ length must be ((_tcslen(pszDest) + min(cbMaxAppend / sizeof(TCHAR), _tcslen(pszSrc)) + 1) * sizeof(TCHAR)
+ to hold all of the combine string plus the null
+ terminator.
+
+ pszSrc - source string
+
+ cbMaxAppend - maximum number of bytes to append
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function appended any data, the result will point to the
+ null termination character
+
+ pcbRemaining - if pcbRemaining is non-null, the function will return the
+ number of bytes left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT(""))
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any pre-existing
+ or truncated string
+
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any pre-existing or
+ truncated string
+
+ STRSAFE_NO_TRUNCATION
+ if the function returns STRSAFE_E_INSUFFICIENT_BUFFER, pszDest
+ will not contain a truncated string, it will remain unchanged.
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
+ is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
+ may be NULL. An error may still be returned even though NULLS are ignored
+ due to insufficient space.
+
+Return Value:
+
+ S_OK - if all of pszSrc or the first cbMaxAppend bytes were
+ concatenated to pszDest and the resultant dest string
+ was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the operation
+ failed due to insufficient space. When this error
+ occurs, the destination buffer is modified to contain
+ a truncated version of the ideal result and is null
+ terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCbCatNExA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbMaxAppend, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCbCatNExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbMaxAppend, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
+#ifdef UNICODE
+#define StringCbCatNEx StringCbCatNExW
+#else
+#define StringCbCatNEx StringCbCatNExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbCatNExA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbMaxAppend, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cchMaxAppend;
+
+ cchMaxAppend = cbMaxAppend / sizeof(char);
+
+ hr = StringCatNExWorkerA(pszDest, cchDest, cbDest, pszSrc, cchMaxAppend, ppszDestEnd, &cchRemaining, dwFlags);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
+ *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCbCatNExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbMaxAppend, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(wchar_t);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cchMaxAppend;
+
+ cchMaxAppend = cbMaxAppend / sizeof(wchar_t);
+
+ hr = StringCatNExWorkerW(pszDest, cchDest, cbDest, pszSrc, cchMaxAppend, ppszDestEnd, &cchRemaining, dwFlags);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
+ *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
+ }
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI
+StringCchVPrintf(
+ OUT LPTSTR pszDest,
+ IN size_t cchDest,
+ IN LPCTSTR pszFormat,
+ IN va_list argList
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'vsprintf'.
+ The size of the destination buffer (in characters) is a parameter and
+ this function will not write past the end of this buffer and it will
+ ALWAYS null terminate the destination buffer (unless it is zero length).
+
+ This function returns a hresult, and not a pointer. It returns
+ S_OK if the string was printed without truncation and null terminated,
+ otherwise it will return a failure code. In failure cases it will return
+ a truncated version of the ideal result.
+
+Arguments:
+
+ pszDest - destination string
+
+ cchDest - size of destination buffer in characters
+ length must be sufficient to hold the resulting formatted
+ string, including the null terminator.
+
+ pszFormat - format string which must be null terminated
+
+ argList - va_list from the variable arguments according to the
+ stdarg.h convention
+
+Notes:
+ Behavior is undefined if destination, format strings or any arguments
+ strings overlap.
+
+ pszDest and pszFormat should not be NULL. See StringCchVPrintfEx if you
+ require the handling of NULL values.
+
+Return Value:
+
+ S_OK - if there was sufficient space in the dest buffer for
+ the resultant string and it was null terminated.
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the print
+ operation failed due to insufficient space. When this
+ error occurs, the destination buffer is modified to
+ contain a truncated version of the ideal result and is
+ null terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCchVPrintfA(char* pszDest, size_t cchDest, const char* pszFormat, va_list argList);
+STRSAFEAPI StringCchVPrintfW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, va_list argList);
+#ifdef UNICODE
+#define StringCchVPrintf StringCchVPrintfW
+#else
+#define StringCchVPrintf StringCchVPrintfA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchVPrintfA(char* pszDest, size_t cchDest, const char* pszFormat, va_list argList)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringVPrintfWorkerA(pszDest, cchDest, pszFormat, argList);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCchVPrintfW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, va_list argList)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI
+StringCbVPrintf(
+ OUT LPTSTR pszDest,
+ IN size_t cbDest,
+ IN LPCTSTR pszFormat,
+ IN va_list argList
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'vsprintf'.
+ The size of the destination buffer (in bytes) is a parameter and
+ this function will not write past the end of this buffer and it will
+ ALWAYS null terminate the destination buffer (unless it is zero length).
+
+ This function returns a hresult, and not a pointer. It returns
+ S_OK if the string was printed without truncation and null terminated,
+ otherwise it will return a failure code. In failure cases it will return
+ a truncated version of the ideal result.
+
+Arguments:
+
+ pszDest - destination string
+
+ cbDest - size of destination buffer in bytes
+ length must be sufficient to hold the resulting formatted
+ string, including the null terminator.
+
+ pszFormat - format string which must be null terminated
+
+ argList - va_list from the variable arguments according to the
+ stdarg.h convention
+
+Notes:
+ Behavior is undefined if destination, format strings or any arguments
+ strings overlap.
+
+ pszDest and pszFormat should not be NULL. See StringCbVPrintfEx if you
+ require the handling of NULL values.
+
+
+Return Value:
+
+ S_OK - if there was sufficient space in the dest buffer for
+ the resultant string and it was null terminated.
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the print
+ operation failed due to insufficient space. When this
+ error occurs, the destination buffer is modified to
+ contain a truncated version of the ideal result and is
+ null terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCbVPrintfA(char* pszDest, size_t cbDest, const char* pszFormat, va_list argList);
+STRSAFEAPI StringCbVPrintfW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszFormat, va_list argList);
+#ifdef UNICODE
+#define StringCbVPrintf StringCbVPrintfW
+#else
+#define StringCbVPrintf StringCbVPrintfA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbVPrintfA(char* pszDest, size_t cbDest, const char* pszFormat, va_list argList)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringVPrintfWorkerA(pszDest, cchDest, pszFormat, argList);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCbVPrintfW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszFormat, va_list argList)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ cchDest = cbDest / sizeof(wchar_t);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI
+StringCchPrintf(
+ OUT LPTSTR pszDest,
+ IN size_t cchDest,
+ IN LPCTSTR pszFormat,
+ ...
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'sprintf'.
+ The size of the destination buffer (in characters) is a parameter and
+ this function will not write past the end of this buffer and it will
+ ALWAYS null terminate the destination buffer (unless it is zero length).
+
+ This function returns a hresult, and not a pointer. It returns
+ S_OK if the string was printed without truncation and null terminated,
+ otherwise it will return a failure code. In failure cases it will return
+ a truncated version of the ideal result.
+
+Arguments:
+
+ pszDest - destination string
+
+ cchDest - size of destination buffer in characters
+ length must be sufficient to hold the resulting formatted
+ string, including the null terminator.
+
+ pszFormat - format string which must be null terminated
+
+ ... - additional parameters to be formatted according to
+ the format string
+
+Notes:
+ Behavior is undefined if destination, format strings or any arguments
+ strings overlap.
+
+ pszDest and pszFormat should not be NULL. See StringCchPrintfEx if you
+ require the handling of NULL values.
+
+Return Value:
+
+ S_OK - if there was sufficient space in the dest buffer for
+ the resultant string and it was null terminated.
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the print
+ operation failed due to insufficient space. When this
+ error occurs, the destination buffer is modified to
+ contain a truncated version of the ideal result and is
+ null terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCchPrintfA(char* pszDest, size_t cchDest, const char* pszFormat, ...);
+STRSAFEAPI StringCchPrintfW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, ...);
+#ifdef UNICODE
+#define StringCchPrintf StringCchPrintfW
+#else
+#define StringCchPrintf StringCchPrintfA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchPrintfA(char* pszDest, size_t cchDest, const char* pszFormat, ...)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ va_list argList;
+
+ va_start(argList, pszFormat);
+
+ hr = StringVPrintfWorkerA(pszDest, cchDest, pszFormat, argList);
+
+ va_end(argList);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCchPrintfW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, ...)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ va_list argList;
+
+ va_start(argList, pszFormat);
+
+ hr = StringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList);
+
+ va_end(argList);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI
+StringCbPrintf(
+ OUT LPTSTR pszDest,
+ IN size_t cbDest,
+ IN LPCTSTR pszFormat,
+ ...
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'sprintf'.
+ The size of the destination buffer (in bytes) is a parameter and
+ this function will not write past the end of this buffer and it will
+ ALWAYS null terminate the destination buffer (unless it is zero length).
+
+ This function returns a hresult, and not a pointer. It returns
+ S_OK if the string was printed without truncation and null terminated,
+ otherwise it will return a failure code. In failure cases it will return
+ a truncated version of the ideal result.
+
+Arguments:
+
+ pszDest - destination string
+
+ cbDest - size of destination buffer in bytes
+ length must be sufficient to hold the resulting formatted
+ string, including the null terminator.
+
+ pszFormat - format string which must be null terminated
+
+ ... - additional parameters to be formatted according to
+ the format string
+
+Notes:
+ Behavior is undefined if destination, format strings or any arguments
+ strings overlap.
+
+ pszDest and pszFormat should not be NULL. See StringCbPrintfEx if you
+ require the handling of NULL values.
+
+
+Return Value:
+
+ S_OK - if there was sufficient space in the dest buffer for
+ the resultant string and it was null terminated.
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the print
+ operation failed due to insufficient space. When this
+ error occurs, the destination buffer is modified to
+ contain a truncated version of the ideal result and is
+ null terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCbPrintfA(char* pszDest, size_t cbDest, const char* pszFormat, ...);
+STRSAFEAPI StringCbPrintfW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszFormat, ...);
+#ifdef UNICODE
+#define StringCbPrintf StringCbPrintfW
+#else
+#define StringCbPrintf StringCbPrintfA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbPrintfA(char* pszDest, size_t cbDest, const char* pszFormat, ...)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ va_list argList;
+
+ va_start(argList, pszFormat);
+
+ hr = StringVPrintfWorkerA(pszDest, cchDest, pszFormat, argList);
+
+ va_end(argList);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCbPrintfW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszFormat, ...)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ cchDest = cbDest / sizeof(wchar_t);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ va_list argList;
+
+ va_start(argList, pszFormat);
+
+ hr = StringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList);
+
+ va_end(argList);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI
+StringCchPrintfEx(
+ OUT LPTSTR pszDest OPTIONAL,
+ IN size_t cchDest,
+ OUT LPTSTR* ppszDestEnd OPTIONAL,
+ OUT size_t* pcchRemaining OPTIONAL,
+ IN DWORD dwFlags,
+ IN LPCTSTR pszFormat OPTIONAL,
+ ...
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'sprintf' with
+ some additional parameters. In addition to functionality provided by
+ StringCchPrintf, this routine also returns a pointer to the end of the
+ destination string and the number of characters left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string
+
+ cchDest - size of destination buffer in characters.
+ length must be sufficient to contain the resulting
+ formatted string plus the null terminator.
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function printed any data, the result will point to the
+ null termination character
+
+ pcchRemaining - if pcchRemaining is non-null, the function will return
+ the number of characters left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT(""))
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any truncated
+ string returned when the failure is
+ STRSAFE_E_INSUFFICIENT_BUFFER
+
+ STRSAFE_NO_TRUNCATION /
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any truncated string
+ returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
+
+ pszFormat - format string which must be null terminated
+
+ ... - additional parameters to be formatted according to
+ the format string
+
+Notes:
+ Behavior is undefined if destination, format strings or any arguments
+ strings overlap.
+
+ pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS
+ flag is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and
+ pszFormat may be NULL. An error may still be returned even though NULLS
+ are ignored due to insufficient space.
+
+Return Value:
+
+ S_OK - if there was source data and it was all concatenated and
+ the resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the print
+ operation failed due to insufficient space. When this
+ error occurs, the destination buffer is modified to
+ contain a truncated version of the ideal result and is
+ null terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCchPrintfExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, ...);
+STRSAFEAPI StringCchPrintfExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, ...);
+#ifdef UNICODE
+#define StringCchPrintfEx StringCchPrintfExW
+#else
+#define StringCchPrintfEx StringCchPrintfExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchPrintfExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, ...)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+ va_list argList;
+
+ // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
+ cbDest = cchDest * sizeof(char);
+ va_start(argList, pszFormat);
+
+ hr = StringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList);
+
+ va_end(argList);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCchPrintfExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, ...)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+ va_list argList;
+
+ // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
+ cbDest = cchDest * sizeof(wchar_t);
+ va_start(argList, pszFormat);
+
+ hr = StringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList);
+
+ va_end(argList);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI
+StringCbPrintfEx(
+ OUT LPTSTR pszDest OPTIONAL,
+ IN size_t cbDest,
+ OUT LPTSTR* ppszDestEnd OPTIONAL,
+ OUT size_t* pcbRemaining OPTIONAL,
+ IN DWORD dwFlags,
+ IN LPCTSTR pszFormat OPTIONAL,
+ ...
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'sprintf' with
+ some additional parameters. In addition to functionality provided by
+ StringCbPrintf, this routine also returns a pointer to the end of the
+ destination string and the number of bytes left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string
+
+ cbDest - size of destination buffer in bytes.
+ length must be sufficient to contain the resulting
+ formatted string plus the null terminator.
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function printed any data, the result will point to the
+ null termination character
+
+ pcbRemaining - if pcbRemaining is non-null, the function will return
+ the number of bytes left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT(""))
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any truncated
+ string returned when the failure is
+ STRSAFE_E_INSUFFICIENT_BUFFER
+
+ STRSAFE_NO_TRUNCATION /
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any truncated string
+ returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
+
+ pszFormat - format string which must be null terminated
+
+ ... - additional parameters to be formatted according to
+ the format string
+
+Notes:
+ Behavior is undefined if destination, format strings or any arguments
+ strings overlap.
+
+ pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS
+ flag is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and
+ pszFormat may be NULL. An error may still be returned even though NULLS
+ are ignored due to insufficient space.
+
+Return Value:
+
+ S_OK - if there was source data and it was all concatenated and
+ the resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the print
+ operation failed due to insufficient space. When this
+ error occurs, the destination buffer is modified to
+ contain a truncated version of the ideal result and is
+ null terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCbPrintfExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const char* pszFormat, ...);
+STRSAFEAPI StringCbPrintfExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const wchar_t* pszFormat, ...);
+#ifdef UNICODE
+#define StringCbPrintfEx StringCbPrintfExW
+#else
+#define StringCbPrintfEx StringCbPrintfExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbPrintfExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const char* pszFormat, ...)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ va_list argList;
+
+ va_start(argList, pszFormat);
+
+ hr = StringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList);
+
+ va_end(argList);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
+ *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCbPrintfExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const wchar_t* pszFormat, ...)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(wchar_t);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ va_list argList;
+
+ va_start(argList, pszFormat);
+
+ hr = StringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList);
+
+ va_end(argList);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
+ *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
+ }
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI
+StringCchVPrintfEx(
+ OUT LPTSTR pszDest OPTIONAL,
+ IN size_t cchDest,
+ OUT LPTSTR* ppszDestEnd OPTIONAL,
+ OUT size_t* pcchRemaining OPTIONAL,
+ IN DWORD dwFlags,
+ IN LPCTSTR pszFormat OPTIONAL,
+ IN va_list argList
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'vsprintf' with
+ some additional parameters. In addition to functionality provided by
+ StringCchVPrintf, this routine also returns a pointer to the end of the
+ destination string and the number of characters left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string
+
+ cchDest - size of destination buffer in characters.
+ length must be sufficient to contain the resulting
+ formatted string plus the null terminator.
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function printed any data, the result will point to the
+ null termination character
+
+ pcchRemaining - if pcchRemaining is non-null, the function will return
+ the number of characters left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT(""))
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any truncated
+ string returned when the failure is
+ STRSAFE_E_INSUFFICIENT_BUFFER
+
+ STRSAFE_NO_TRUNCATION /
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any truncated string
+ returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
+
+ pszFormat - format string which must be null terminated
+
+ argList - va_list from the variable arguments according to the
+ stdarg.h convention
+
+Notes:
+ Behavior is undefined if destination, format strings or any arguments
+ strings overlap.
+
+ pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS
+ flag is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and
+ pszFormat may be NULL. An error may still be returned even though NULLS
+ are ignored due to insufficient space.
+
+Return Value:
+
+ S_OK - if there was source data and it was all concatenated and
+ the resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the print
+ operation failed due to insufficient space. When this
+ error occurs, the destination buffer is modified to
+ contain a truncated version of the ideal result and is
+ null terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCchVPrintfExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList);
+STRSAFEAPI StringCchVPrintfExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList);
+#ifdef UNICODE
+#define StringCchVPrintfEx StringCchVPrintfExW
+#else
+#define StringCchVPrintfEx StringCchVPrintfExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchVPrintfExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
+ cbDest = cchDest * sizeof(char);
+
+ hr = StringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCchVPrintfExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
+ cbDest = cchDest * sizeof(wchar_t);
+
+ hr = StringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI
+StringCbVPrintfEx(
+ OUT LPTSTR pszDest OPTIONAL,
+ IN size_t cbDest,
+ OUT LPTSTR* ppszDestEnd OPTIONAL,
+ OUT size_t* pcbRemaining OPTIONAL,
+ IN DWORD dwFlags,
+ IN LPCTSTR pszFormat OPTIONAL,
+ IN va_list argList
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'vsprintf' with
+ some additional parameters. In addition to functionality provided by
+ StringCbVPrintf, this routine also returns a pointer to the end of the
+ destination string and the number of characters left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string
+
+ cbDest - size of destination buffer in bytes.
+ length must be sufficient to contain the resulting
+ formatted string plus the null terminator.
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return
+ a pointer to the end of the destination string. If the
+ function printed any data, the result will point to the
+ null termination character
+
+ pcbRemaining - if pcbRemaining is non-null, the function will return
+ the number of bytes left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT(""))
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any truncated
+ string returned when the failure is
+ STRSAFE_E_INSUFFICIENT_BUFFER
+
+ STRSAFE_NO_TRUNCATION /
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any truncated string
+ returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
+
+ pszFormat - format string which must be null terminated
+
+ argList - va_list from the variable arguments according to the
+ stdarg.h convention
+
+Notes:
+ Behavior is undefined if destination, format strings or any arguments
+ strings overlap.
+
+ pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS
+ flag is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and
+ pszFormat may be NULL. An error may still be returned even though NULLS
+ are ignored due to insufficient space.
+
+Return Value:
+
+ S_OK - if there was source data and it was all concatenated and
+ the resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the print
+ operation failed due to insufficient space. When this
+ error occurs, the destination buffer is modified to
+ contain a truncated version of the ideal result and is
+ null terminated. This is useful for situations where
+ truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCbVPrintfExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList);
+STRSAFEAPI StringCbVPrintfExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList);
+#ifdef UNICODE
+#define StringCbVPrintfEx StringCbVPrintfExW
+#else
+#define StringCbVPrintfEx StringCbVPrintfExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbVPrintfExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
+ *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCbVPrintfExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(wchar_t);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
+ *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
+ }
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI
+StringCchGets(
+ OUT LPTSTR pszDest,
+ IN size_t cchDest
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'gets'.
+ The size of the destination buffer (in characters) is a parameter and
+ this function will not write past the end of this buffer and it will
+ ALWAYS null terminate the destination buffer (unless it is zero length).
+
+ This routine is not a replacement for fgets. That function does not replace
+ newline characters with a null terminator.
+
+ This function returns a hresult, and not a pointer. It returns
+ S_OK if any characters were read from stdin and copied to pszDest and
+ pszDest was null terminated, otherwise it will return a failure code.
+
+Arguments:
+
+ pszDest - destination string
+
+ cchDest - size of destination buffer in characters.
+
+Notes:
+ pszDest should not be NULL. See StringCchGetsEx if you require the handling
+ of NULL values.
+
+ cchDest must be > 1 for this function to succeed.
+
+Return Value:
+
+ S_OK - data was read from stdin and copied, and the resultant
+ dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_END_OF_FILE /
+ HRESULT_CODE(hr) == ERROR_HANDLE_EOF
+ - this return value indicates an error or end-of-file
+ condition, use feof or ferror to determine which one has
+ occured.
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that there was
+ insufficient space in the destination buffer to copy any
+ data
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function.
+
+--*/
+
+#ifndef STRSAFE_LIB_IMPL
+STRSAFE_INLINE_API StringCchGetsA(char* pszDest, size_t cchDest);
+STRSAFE_INLINE_API StringCchGetsW(wchar_t* pszDest, size_t cchDest);
+#ifdef UNICODE
+#define StringCchGets StringCchGetsW
+#else
+#define StringCchGets StringCchGetsA
+#endif // !UNICODE
+
+STRSAFE_INLINE_API StringCchGetsA(char* pszDest, size_t cchDest)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
+ cbDest = cchDest * sizeof(char);
+
+ hr = StringGetsExWorkerA(pszDest, cchDest, cbDest, NULL, NULL, 0);
+ }
+
+ return hr;
+}
+
+STRSAFE_INLINE_API StringCchGetsW(wchar_t* pszDest, size_t cchDest)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
+ cbDest = cchDest * sizeof(wchar_t);
+
+ hr = StringGetsExWorkerW(pszDest, cchDest, cbDest, NULL, NULL, 0);
+ }
+
+ return hr;
+}
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+#endif // !STRSAFE_LIB_IMPL
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI
+StringCbGets(
+ OUT LPTSTR pszDest,
+ IN size_t cbDest
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'gets'.
+ The size of the destination buffer (in bytes) is a parameter and
+ this function will not write past the end of this buffer and it will
+ ALWAYS null terminate the destination buffer (unless it is zero length).
+
+ This routine is not a replacement for fgets. That function does not replace
+ newline characters with a null terminator.
+
+ This function returns a hresult, and not a pointer. It returns
+ S_OK if any characters were read from stdin and copied to pszDest
+ and pszDest was null terminated, otherwise it will return a failure code.
+
+Arguments:
+
+ pszDest - destination string
+
+ cbDest - size of destination buffer in bytes.
+
+Notes:
+ pszDest should not be NULL. See StringCbGetsEx if you require the handling
+ of NULL values.
+
+ cbDest must be > sizeof(TCHAR) for this function to succeed.
+
+Return Value:
+
+ S_OK - data was read from stdin and copied, and the resultant
+ dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_END_OF_FILE /
+ HRESULT_CODE(hr) == ERROR_HANDLE_EOF
+ - this return value indicates an error or end-of-file
+ condition, use feof or ferror to determine which one has
+ occured.
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that there was
+ insufficient space in the destination buffer to copy any
+ data
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function.
+
+--*/
+
+#ifndef STRSAFE_LIB_IMPL
+STRSAFE_INLINE_API StringCbGetsA(char* pszDest, size_t cbDest);
+STRSAFE_INLINE_API StringCbGetsW(wchar_t* pszDest, size_t cbDest);
+#ifdef UNICODE
+#define StringCbGets StringCbGetsW
+#else
+#define StringCbGets StringCbGetsA
+#endif // !UNICODE
+
+STRSAFE_INLINE_API StringCbGetsA(char* pszDest, size_t cbDest)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ // convert to count of characters
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringGetsExWorkerA(pszDest, cchDest, cbDest, NULL, NULL, 0);
+ }
+
+ return hr;
+}
+
+STRSAFE_INLINE_API StringCbGetsW(wchar_t* pszDest, size_t cbDest)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ // convert to count of characters
+ cchDest = cbDest / sizeof(wchar_t);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringGetsExWorkerW(pszDest, cchDest, cbDest, NULL, NULL, 0);
+ }
+
+ return hr;
+}
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+#endif // !STRSAFE_LIB_IMPL
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI
+StringCchGetsEx(
+ OUT LPTSTR pszDest OPTIONAL,
+ IN size_t cchDest,
+ OUT LPTSTR* ppszDestEnd OPTIONAL,
+ OUT size_t* pcchRemaining OPTIONAL,
+ IN DWORD dwFlags
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'gets' with
+ some additional parameters. In addition to functionality provided by
+ StringCchGets, this routine also returns a pointer to the end of the
+ destination string and the number of characters left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string
+
+ cchDest - size of destination buffer in characters.
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function copied any data, the result will point to the
+ null termination character
+
+ pcchRemaining - if pcchRemaining is non-null, the function will return the
+ number of characters left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT("")).
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated.
+
+ STRSAFE_NO_TRUNCATION /
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string.
+
+Notes:
+ pszDest should not be NULL unless the STRSAFE_IGNORE_NULLS flag is specified.
+ If STRSAFE_IGNORE_NULLS is passed and pszDest is NULL, an error may still be
+ returned even though NULLS are ignored
+
+ cchDest must be > 1 for this function to succeed.
+
+Return Value:
+
+ S_OK - data was read from stdin and copied, and the resultant
+ dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_END_OF_FILE /
+ HRESULT_CODE(hr) == ERROR_HANDLE_EOF
+ - this return value indicates an error or end-of-file
+ condition, use feof or ferror to determine which one has
+ occured.
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that there was
+ insufficient space in the destination buffer to copy any
+ data
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function.
+
+--*/
+
+#ifndef STRSAFE_LIB_IMPL
+STRSAFE_INLINE_API StringCchGetsExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFE_INLINE_API StringCchGetsExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+#ifdef UNICODE
+#define StringCchGetsEx StringCchGetsExW
+#else
+#define StringCchGetsEx StringCchGetsExA
+#endif // !UNICODE
+
+STRSAFE_INLINE_API StringCchGetsExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
+ cbDest = cchDest * sizeof(char);
+
+ hr = StringGetsExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags);
+ }
+
+ return hr;
+}
+
+STRSAFE_INLINE_API StringCchGetsExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
+ cbDest = cchDest * sizeof(wchar_t);
+
+ hr = StringGetsExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags);
+ }
+
+ return hr;
+}
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+#endif // !STRSAFE_LIB_IMPL
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI
+StringCbGetsEx(
+ OUT LPTSTR pszDest OPTIONAL,
+ IN size_t cbDest,
+ OUT LPTSTR* ppszDestEnd OPTIONAL,
+ OUT size_t* pcbRemaining OPTIONAL,
+ IN DWORD dwFlags
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'gets' with
+ some additional parameters. In addition to functionality provided by
+ StringCbGets, this routine also returns a pointer to the end of the
+ destination string and the number of characters left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string
+
+ cbDest - size of destination buffer in bytes.
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function copied any data, the result will point to the
+ null termination character
+
+ pcbRemaining - if pbRemaining is non-null, the function will return the
+ number of bytes left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT("")).
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated.
+
+ STRSAFE_NO_TRUNCATION /
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string.
+
+Notes:
+ pszDest should not be NULL unless the STRSAFE_IGNORE_NULLS flag is specified.
+ If STRSAFE_IGNORE_NULLS is passed and pszDest is NULL, an error may still be
+ returned even though NULLS are ignored
+
+ cbDest must be > sizeof(TCHAR) for this function to succeed
+
+Return Value:
+
+ S_OK - data was read from stdin and copied, and the resultant
+ dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ STRSAFE_E_END_OF_FILE /
+ HRESULT_CODE(hr) == ERROR_HANDLE_EOF
+ - this return value indicates an error or end-of-file
+ condition, use feof or ferror to determine which one has
+ occured.
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that there was
+ insufficient space in the destination buffer to copy any
+ data
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function.
+
+--*/
+
+#ifndef STRSAFE_LIB_IMPL
+STRSAFE_INLINE_API StringCbGetsExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pbRemaining, unsigned long dwFlags);
+STRSAFE_INLINE_API StringCbGetsExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
+#ifdef UNICODE
+#define StringCbGetsEx StringCbGetsExW
+#else
+#define StringCbGetsEx StringCbGetsExA
+#endif // !UNICODE
+
+STRSAFE_INLINE_API StringCbGetsExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringGetsExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags);
+ }
+
+ if (SUCCEEDED(hr) ||
+ (hr == STRSAFE_E_INSUFFICIENT_BUFFER) ||
+ (hr == STRSAFE_E_END_OF_FILE))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
+ *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
+ }
+ }
+
+ return hr;
+}
+
+STRSAFE_INLINE_API StringCbGetsExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(wchar_t);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringGetsExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags);
+ }
+
+ if (SUCCEEDED(hr) ||
+ (hr == STRSAFE_E_INSUFFICIENT_BUFFER) ||
+ (hr == STRSAFE_E_END_OF_FILE))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
+ *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
+ }
+ }
+
+ return hr;
+}
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+#endif // !STRSAFE_LIB_IMPL
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI
+StringCchLength(
+ IN LPCTSTR psz,
+ IN size_t cchMax,
+ OUT size_t* pcch OPTIONAL
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strlen'.
+ It is used to make sure a string is not larger than a given length, and
+ it optionally returns the current length in characters not including
+ the null terminator.
+
+ This function returns a hresult, and not a pointer. It returns
+ S_OK if the string is non-null and the length including the null
+ terminator is less than or equal to cchMax characters.
+
+Arguments:
+
+ psz - string to check the length of
+
+ cchMax - maximum number of characters including the null terminator
+ that psz is allowed to contain
+
+ pcch - if the function succeeds and pcch is non-null, the current length
+ in characters of psz excluding the null terminator will be returned.
+ This out parameter is equivalent to the return value of strlen(psz)
+
+Notes:
+ psz can be null but the function will fail
+
+ cchMax should be greater than zero or the function will fail
+
+Return Value:
+
+ S_OK - psz is non-null and the length including the null
+ terminator is less than or equal to cchMax characters
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function.
+
+--*/
+
+STRSAFEAPI StringCchLengthA(const char* psz, size_t cchMax, size_t* pcch);
+STRSAFEAPI StringCchLengthW(const wchar_t* psz, size_t cchMax, size_t* pcch);
+#ifdef UNICODE
+#define StringCchLength StringCchLengthW
+#else
+#define StringCchLength StringCchLengthA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchLengthA(const char* psz, size_t cchMax, size_t* pcch)
+{
+ HRESULT hr;
+
+ if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringLengthWorkerA(psz, cchMax, pcch);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCchLengthW(const wchar_t* psz, size_t cchMax, size_t* pcch)
+{
+ HRESULT hr;
+
+ if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringLengthWorkerW(psz, cchMax, pcch);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI
+StringCbLength(
+ IN LPCTSTR psz,
+ IN size_t cbMax,
+ OUT size_t* pcb OPTIONAL
+ );
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strlen'.
+ It is used to make sure a string is not larger than a given length, and
+ it optionally returns the current length in bytes not including
+ the null terminator.
+
+ This function returns a hresult, and not a pointer. It returns
+ S_OK if the string is non-null and the length including the null
+ terminator is less than or equal to cbMax bytes.
+
+Arguments:
+
+ psz - string to check the length of
+
+ cbMax - maximum number of bytes including the null terminator
+ that psz is allowed to contain
+
+ pcb - if the function succeeds and pcb is non-null, the current length
+ in bytes of psz excluding the null terminator will be returned.
+ This out parameter is equivalent to the return value of strlen(psz) * sizeof(TCHAR)
+
+Notes:
+ psz can be null but the function will fail
+
+ cbMax should be greater than or equal to sizeof(TCHAR) or the function will fail
+
+Return Value:
+
+ S_OK - psz is non-null and the length including the null
+ terminator is less than or equal to cbMax bytes
+
+ failure - you can use the macro HRESULT_CODE() to get a win32
+ error code for all hresult failure cases
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function.
+
+--*/
+
+STRSAFEAPI StringCbLengthA(const char* psz, size_t cchMax, size_t* pcch);
+STRSAFEAPI StringCbLengthW(const wchar_t* psz, size_t cchMax, size_t* pcch);
+#ifdef UNICODE
+#define StringCbLength StringCbLengthW
+#else
+#define StringCbLength StringCbLengthA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbLengthA(const char* psz, size_t cbMax, size_t* pcb)
+{
+ HRESULT hr;
+ size_t cchMax;
+ size_t cch = 0;
+
+ cchMax = cbMax / sizeof(char);
+
+ if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringLengthWorkerA(psz, cchMax, &cch);
+ }
+
+ if (SUCCEEDED(hr) && pcb)
+ {
+ // safe to multiply cch * sizeof(char) since cch < STRSAFE_MAX_CCH and sizeof(char) is 1
+ *pcb = cch * sizeof(char);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCbLengthW(const wchar_t* psz, size_t cbMax, size_t* pcb)
+{
+ HRESULT hr;
+ size_t cchMax;
+ size_t cch = 0;
+
+ cchMax = cbMax / sizeof(wchar_t);
+
+ if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringLengthWorkerW(psz, cchMax, &cch);
+ }
+
+ if (SUCCEEDED(hr) && pcb)
+ {
+ // safe to multiply cch * sizeof(wchar_t) since cch < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
+ *pcb = cch * sizeof(wchar_t);
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+// these are the worker functions that actually do the work
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCopyWorkerA(char* pszDest, size_t cchDest, const char* pszSrc)
+{
+ HRESULT hr = S_OK;
+
+ if (cchDest == 0)
+ {
+ // can not null terminate a zero-byte dest buffer
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ while (cchDest && (*pszSrc != '\0'))
+ {
+ *pszDest++ = *pszSrc++;
+ cchDest--;
+ }
+
+ if (cchDest == 0)
+ {
+ // we are going to truncate pszDest
+ pszDest--;
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+
+ *pszDest= '\0';
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCopyWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc)
+{
+ HRESULT hr = S_OK;
+
+ if (cchDest == 0)
+ {
+ // can not null terminate a zero-byte dest buffer
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ while (cchDest && (*pszSrc != L'\0'))
+ {
+ *pszDest++ = *pszSrc++;
+ cchDest--;
+ }
+
+ if (cchDest == 0)
+ {
+ // we are going to truncate pszDest
+ pszDest--;
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+
+ *pszDest= L'\0';
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCopyExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr = S_OK;
+ char* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+
+ // ASSERT(cbDest == (cchDest * sizeof(char)) ||
+ // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest != 0) || (cbDest != 0))
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+
+ if (pszSrc == NULL)
+ {
+ pszSrc = "";
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = 0;
+
+ // only fail if there was actually src data to copy
+ if (*pszSrc != '\0')
+ {
+ if (pszDest == NULL)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ else
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ while (cchRemaining && (*pszSrc != '\0'))
+ {
+ *pszDestEnd++= *pszSrc++;
+ cchRemaining--;
+ }
+
+ if (cchRemaining > 0)
+ {
+ if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
+ {
+ memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(char)) + (cbDest % sizeof(char)));
+ }
+ }
+ else
+ {
+ // we are going to truncate pszDest
+ pszDestEnd--;
+ cchRemaining++;
+
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+
+ *pszDestEnd = '\0';
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = '\0';
+ }
+ }
+
+ if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = '\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCopyExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr = S_OK;
+ wchar_t* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+
+ // ASSERT(cbDest == (cchDest * sizeof(wchar_t)) ||
+ // cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest != 0) || (cbDest != 0))
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+
+ if (pszSrc == NULL)
+ {
+ pszSrc = L"";
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = 0;
+
+ // only fail if there was actually src data to copy
+ if (*pszSrc != L'\0')
+ {
+ if (pszDest == NULL)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ else
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ while (cchRemaining && (*pszSrc != L'\0'))
+ {
+ *pszDestEnd++= *pszSrc++;
+ cchRemaining--;
+ }
+
+ if (cchRemaining > 0)
+ {
+ if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
+ {
+ memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
+ }
+ }
+ else
+ {
+ // we are going to truncate pszDest
+ pszDestEnd--;
+ cchRemaining++;
+
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+
+ *pszDestEnd = L'\0';
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+
+ if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCopyNWorkerA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc)
+{
+ HRESULT hr = S_OK;
+
+ if (cchDest == 0)
+ {
+ // can not null terminate a zero-byte dest buffer
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ while (cchDest && cchSrc && (*pszSrc != '\0'))
+ {
+ *pszDest++= *pszSrc++;
+ cchDest--;
+ cchSrc--;
+ }
+
+ if (cchDest == 0)
+ {
+ // we are going to truncate pszDest
+ pszDest--;
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+
+ *pszDest= '\0';
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCopyNWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc)
+{
+ HRESULT hr = S_OK;
+
+ if (cchDest == 0)
+ {
+ // can not null terminate a zero-byte dest buffer
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ while (cchDest && cchSrc && (*pszSrc != L'\0'))
+ {
+ *pszDest++= *pszSrc++;
+ cchDest--;
+ cchSrc--;
+ }
+
+ if (cchDest == 0)
+ {
+ // we are going to truncate pszDest
+ pszDest--;
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+
+ *pszDest= L'\0';
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCopyNExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, size_t cchSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr = S_OK;
+ char* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+
+ // ASSERT(cbDest == (cchDest * sizeof(char)) ||
+ // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest != 0) || (cbDest != 0))
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+
+ if (pszSrc == NULL)
+ {
+ pszSrc = "";
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = 0;
+
+ // only fail if there was actually src data to copy
+ if (*pszSrc != '\0')
+ {
+ if (pszDest == NULL)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ else
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ while (cchRemaining && cchSrc && (*pszSrc != '\0'))
+ {
+ *pszDestEnd++= *pszSrc++;
+ cchRemaining--;
+ cchSrc--;
+ }
+
+ if (cchRemaining > 0)
+ {
+ if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
+ {
+ memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(char)) + (cbDest % sizeof(char)));
+ }
+ }
+ else
+ {
+ // we are going to truncate pszDest
+ pszDestEnd--;
+ cchRemaining++;
+
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+
+ *pszDestEnd = '\0';
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = '\0';
+ }
+ }
+
+ if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = '\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCopyNExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, size_t cchSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr = S_OK;
+ wchar_t* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+
+ // ASSERT(cbDest == (cchDest * sizeof(wchar_t)) ||
+ // cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest != 0) || (cbDest != 0))
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+
+ if (pszSrc == NULL)
+ {
+ pszSrc = L"";
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = 0;
+
+ // only fail if there was actually src data to copy
+ if (*pszSrc != L'\0')
+ {
+ if (pszDest == NULL)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ else
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ while (cchRemaining && cchSrc && (*pszSrc != L'\0'))
+ {
+ *pszDestEnd++= *pszSrc++;
+ cchRemaining--;
+ cchSrc--;
+ }
+
+ if (cchRemaining > 0)
+ {
+ if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
+ {
+ memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
+ }
+ }
+ else
+ {
+ // we are going to truncate pszDest
+ pszDestEnd--;
+ cchRemaining++;
+
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+
+ *pszDestEnd = L'\0';
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+
+ if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCatWorkerA(char* pszDest, size_t cchDest, const char* pszSrc)
+{
+ HRESULT hr;
+ size_t cchDestCurrent;
+
+ hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = StringCopyWorkerA(pszDest + cchDestCurrent,
+ cchDest - cchDestCurrent,
+ pszSrc);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCatWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc)
+{
+ HRESULT hr;
+ size_t cchDestCurrent;
+
+ hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = StringCopyWorkerW(pszDest + cchDestCurrent,
+ cchDest - cchDestCurrent,
+ pszSrc);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCatExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr = S_OK;
+ char* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+
+ // ASSERT(cbDest == (cchDest * sizeof(char)) ||
+ // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cchDestCurrent;
+
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest == 0) && (cbDest == 0))
+ {
+ cchDestCurrent = 0;
+ }
+ else
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+ else
+ {
+ hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ pszDestEnd = pszDest + cchDestCurrent;
+ cchRemaining = cchDest - cchDestCurrent;
+ }
+ }
+
+ if (pszSrc == NULL)
+ {
+ pszSrc = "";
+ }
+ }
+ else
+ {
+ hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ pszDestEnd = pszDest + cchDestCurrent;
+ cchRemaining = cchDest - cchDestCurrent;
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest == 0)
+ {
+ // only fail if there was actually src data to append
+ if (*pszSrc != '\0')
+ {
+ if (pszDest == NULL)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ else
+ {
+ // we handle the STRSAFE_FILL_ON_FAILURE and STRSAFE_NULL_ON_FAILURE cases below, so do not pass
+ // those flags through
+ hr = StringCopyExWorkerA(pszDestEnd,
+ cchRemaining,
+ (cchRemaining * sizeof(char)) + (cbDest % sizeof(char)),
+ pszSrc,
+ &pszDestEnd,
+ &cchRemaining,
+ dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)));
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ // STRSAFE_NO_TRUNCATION is taken care of by StringCopyExWorkerA()
+
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = '\0';
+ }
+ }
+
+ if (dwFlags & STRSAFE_NULL_ON_FAILURE)
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = '\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCatExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr = S_OK;
+ wchar_t* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+
+ // ASSERT(cbDest == (cchDest * sizeof(wchar_t)) ||
+ // cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cchDestCurrent;
+
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest == 0) && (cbDest == 0))
+ {
+ cchDestCurrent = 0;
+ }
+ else
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+ else
+ {
+ hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ pszDestEnd = pszDest + cchDestCurrent;
+ cchRemaining = cchDest - cchDestCurrent;
+ }
+ }
+
+ if (pszSrc == NULL)
+ {
+ pszSrc = L"";
+ }
+ }
+ else
+ {
+ hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ pszDestEnd = pszDest + cchDestCurrent;
+ cchRemaining = cchDest - cchDestCurrent;
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest == 0)
+ {
+ // only fail if there was actually src data to append
+ if (*pszSrc != L'\0')
+ {
+ if (pszDest == NULL)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ else
+ {
+ // we handle the STRSAFE_FILL_ON_FAILURE and STRSAFE_NULL_ON_FAILURE cases below, so do not pass
+ // those flags through
+ hr = StringCopyExWorkerW(pszDestEnd,
+ cchRemaining,
+ (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)),
+ pszSrc,
+ &pszDestEnd,
+ &cchRemaining,
+ dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)));
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ // STRSAFE_NO_TRUNCATION is taken care of by StringCopyExWorkerW()
+
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+
+ if (dwFlags & STRSAFE_NULL_ON_FAILURE)
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCatNWorkerA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend)
+{
+ HRESULT hr;
+ size_t cchDestCurrent;
+
+ hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = StringCopyNWorkerA(pszDest + cchDestCurrent,
+ cchDest - cchDestCurrent,
+ pszSrc,
+ cchMaxAppend);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCatNWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend)
+{
+ HRESULT hr;
+ size_t cchDestCurrent;
+
+ hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = StringCopyNWorkerW(pszDest + cchDestCurrent,
+ cchDest - cchDestCurrent,
+ pszSrc,
+ cchMaxAppend);
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCatNExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, size_t cchMaxAppend, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr = S_OK;
+ char* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+ size_t cchDestCurrent = 0;
+
+ // ASSERT(cbDest == (cchDest * sizeof(char)) ||
+ // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest == 0) && (cbDest == 0))
+ {
+ cchDestCurrent = 0;
+ }
+ else
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+ else
+ {
+ hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ pszDestEnd = pszDest + cchDestCurrent;
+ cchRemaining = cchDest - cchDestCurrent;
+ }
+ }
+
+ if (pszSrc == NULL)
+ {
+ pszSrc = "";
+ }
+ }
+ else
+ {
+ hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ pszDestEnd = pszDest + cchDestCurrent;
+ cchRemaining = cchDest - cchDestCurrent;
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest == 0)
+ {
+ // only fail if there was actually src data to append
+ if (*pszSrc != '\0')
+ {
+ if (pszDest == NULL)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ else
+ {
+ // we handle the STRSAFE_FILL_ON_FAILURE and STRSAFE_NULL_ON_FAILURE cases below, so do not pass
+ // those flags through
+ hr = StringCopyNExWorkerA(pszDestEnd,
+ cchRemaining,
+ (cchRemaining * sizeof(char)) + (cbDest % sizeof(char)),
+ pszSrc,
+ cchMaxAppend,
+ &pszDestEnd,
+ &cchRemaining,
+ dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)));
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ // STRSAFE_NO_TRUNCATION is taken care of by StringCopyNExWorkerA()
+
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = '\0';
+ }
+ }
+
+ if (dwFlags & (STRSAFE_NULL_ON_FAILURE))
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = '\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringCatNExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, size_t cchMaxAppend, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr = S_OK;
+ wchar_t* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+ size_t cchDestCurrent = 0;
+
+
+ // ASSERT(cbDest == (cchDest * sizeof(wchar_t)) ||
+ // cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest == 0) && (cbDest == 0))
+ {
+ cchDestCurrent = 0;
+ }
+ else
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+ else
+ {
+ hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ pszDestEnd = pszDest + cchDestCurrent;
+ cchRemaining = cchDest - cchDestCurrent;
+ }
+ }
+
+ if (pszSrc == NULL)
+ {
+ pszSrc = L"";
+ }
+ }
+ else
+ {
+ hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ pszDestEnd = pszDest + cchDestCurrent;
+ cchRemaining = cchDest - cchDestCurrent;
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest == 0)
+ {
+ // only fail if there was actually src data to append
+ if (*pszSrc != L'\0')
+ {
+ if (pszDest == NULL)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ else
+ {
+ // we handle the STRSAFE_FILL_ON_FAILURE and STRSAFE_NULL_ON_FAILURE cases below, so do not pass
+ // those flags through
+ hr = StringCopyNExWorkerW(pszDestEnd,
+ cchRemaining,
+ (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)),
+ pszSrc,
+ cchMaxAppend,
+ &pszDestEnd,
+ &cchRemaining,
+ dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)));
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ // STRSAFE_NO_TRUNCATION is taken care of by StringCopyNExWorkerW()
+
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+
+ if (dwFlags & (STRSAFE_NULL_ON_FAILURE))
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringVPrintfWorkerA(char* pszDest, size_t cchDest, const char* pszFormat, va_list argList)
+{
+ HRESULT hr = S_OK;
+
+ if (cchDest == 0)
+ {
+ // can not null terminate a zero-byte dest buffer
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ int iRet;
+ size_t cchMax;
+
+ // leave the last space for the null terminator
+ cchMax = cchDest - 1;
+
+ iRet = _vsnprintf(pszDest, cchMax, pszFormat, argList);
+ // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax));
+
+ if ((iRet < 0) || (((size_t)iRet) > cchMax))
+ {
+ // need to null terminate the string
+ pszDest += cchMax;
+ *pszDest = '\0';
+
+ // we have truncated pszDest
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ else if (((size_t)iRet) == cchMax)
+ {
+ // need to null terminate the string
+ pszDest += cchMax;
+ *pszDest = '\0';
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringVPrintfWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, va_list argList)
+{
+ HRESULT hr = S_OK;
+
+ if (cchDest == 0)
+ {
+ // can not null terminate a zero-byte dest buffer
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ int iRet;
+ size_t cchMax;
+
+ // leave the last space for the null terminator
+ cchMax = cchDest - 1;
+
+ iRet = _vsnwprintf(pszDest, cchMax, pszFormat, argList);
+ // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax));
+
+ if ((iRet < 0) || (((size_t)iRet) > cchMax))
+ {
+ // need to null terminate the string
+ pszDest += cchMax;
+ *pszDest = L'\0';
+
+ // we have truncated pszDest
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ else if (((size_t)iRet) == cchMax)
+ {
+ // need to null terminate the string
+ pszDest += cchMax;
+ *pszDest = L'\0';
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringVPrintfExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList)
+{
+ HRESULT hr = S_OK;
+ char* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+
+ // ASSERT(cbDest == (cchDest * sizeof(char)) ||
+ // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest != 0) || (cbDest != 0))
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+
+ if (pszFormat == NULL)
+ {
+ pszFormat = "";
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = 0;
+
+ // only fail if there was actually a non-empty format string
+ if (*pszFormat != '\0')
+ {
+ if (pszDest == NULL)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ else
+ {
+ int iRet;
+ size_t cchMax;
+
+ // leave the last space for the null terminator
+ cchMax = cchDest - 1;
+
+ iRet = _vsnprintf(pszDest, cchMax, pszFormat, argList);
+ // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax));
+
+ if ((iRet < 0) || (((size_t)iRet) > cchMax))
+ {
+ // we have truncated pszDest
+ pszDestEnd = pszDest + cchMax;
+ cchRemaining = 1;
+
+ // need to null terminate the string
+ *pszDestEnd = '\0';
+
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ else if (((size_t)iRet) == cchMax)
+ {
+ // string fit perfectly
+ pszDestEnd = pszDest + cchMax;
+ cchRemaining = 1;
+
+ // need to null terminate the string
+ *pszDestEnd = '\0';
+ }
+ else if (((size_t)iRet) < cchMax)
+ {
+ // there is extra room
+ pszDestEnd = pszDest + iRet;
+ cchRemaining = cchDest - iRet;
+
+ if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
+ {
+ memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(char)) + (cbDest % sizeof(char)));
+ }
+ }
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = '\0';
+ }
+ }
+
+ if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = '\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringVPrintfExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList)
+{
+ HRESULT hr = S_OK;
+ wchar_t* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+
+ // ASSERT(cbDest == (cchDest * sizeof(wchar_t)) ||
+ // cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest != 0) || (cbDest != 0))
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+
+ if (pszFormat == NULL)
+ {
+ pszFormat = L"";
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = 0;
+
+ // only fail if there was actually a non-empty format string
+ if (*pszFormat != L'\0')
+ {
+ if (pszDest == NULL)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ else
+ {
+ int iRet;
+ size_t cchMax;
+
+ // leave the last space for the null terminator
+ cchMax = cchDest - 1;
+
+ iRet = _vsnwprintf(pszDest, cchMax, pszFormat, argList);
+ // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax));
+
+ if ((iRet < 0) || (((size_t)iRet) > cchMax))
+ {
+ // we have truncated pszDest
+ pszDestEnd = pszDest + cchMax;
+ cchRemaining = 1;
+
+ // need to null terminate the string
+ *pszDestEnd = L'\0';
+
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ else if (((size_t)iRet) == cchMax)
+ {
+ // string fit perfectly
+ pszDestEnd = pszDest + cchMax;
+ cchRemaining = 1;
+
+ // need to null terminate the string
+ *pszDestEnd = L'\0';
+ }
+ else if (((size_t)iRet) < cchMax)
+ {
+ // there is extra room
+ pszDestEnd = pszDest + iRet;
+ cchRemaining = cchDest - iRet;
+
+ if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
+ {
+ memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
+ }
+ }
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+
+ if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringLengthWorkerA(const char* psz, size_t cchMax, size_t* pcch)
+{
+ HRESULT hr = S_OK;
+ size_t cchMaxPrev = cchMax;
+
+ while (cchMax && (*psz != '\0'))
+ {
+ psz++;
+ cchMax--;
+ }
+
+ if (cchMax == 0)
+ {
+ // the string is longer than cchMax
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+
+ if (SUCCEEDED(hr) && pcch)
+ {
+ *pcch = cchMaxPrev - cchMax;
+ }
+
+ return hr;
+}
+
+STRSAFEAPI StringLengthWorkerW(const wchar_t* psz, size_t cchMax, size_t* pcch)
+{
+ HRESULT hr = S_OK;
+ size_t cchMaxPrev = cchMax;
+
+ while (cchMax && (*psz != L'\0'))
+ {
+ psz++;
+ cchMax--;
+ }
+
+ if (cchMax == 0)
+ {
+ // the string is longer than cchMax
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+
+ if (SUCCEEDED(hr) && pcch)
+ {
+ *pcch = cchMaxPrev - cchMax;
+ }
+
+ return hr;
+}
+#endif // STRSAFE_INLINE
+
+#ifndef STRSAFE_LIB_IMPL
+STRSAFE_INLINE_API StringGetsExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr = S_OK;
+ char* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+
+ // ASSERT(cbDest == (cchDest * sizeof(char)) ||
+ // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest != 0) || (cbDest != 0))
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest <= 1)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ if (cchDest == 1)
+ {
+ *pszDestEnd = '\0';
+ }
+
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ else
+ {
+ char ch;
+
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ while ((cchRemaining > 1) && (ch = (char)getc(stdin)) != '\n')
+ {
+ if (ch == EOF)
+ {
+ if (pszDestEnd == pszDest)
+ {
+ // we failed to read anything from stdin
+ hr = STRSAFE_E_END_OF_FILE;
+ }
+ break;
+ }
+
+ *pszDestEnd = ch;
+
+ pszDestEnd++;
+ cchRemaining--;
+ }
+
+ if (cchRemaining > 0)
+ {
+ // there is extra room
+ if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
+ {
+ memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(char)) + (cbDest % sizeof(char)));
+ }
+ }
+
+ *pszDestEnd = '\0';
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = '\0';
+ }
+ }
+
+ if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = '\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) ||
+ (hr == STRSAFE_E_INSUFFICIENT_BUFFER) ||
+ (hr == STRSAFE_E_END_OF_FILE))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+
+STRSAFE_INLINE_API StringGetsExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr = S_OK;
+ wchar_t* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+
+ // ASSERT(cbDest == (cchDest * sizeof(char)) ||
+ // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest != 0) || (cbDest != 0))
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest <= 1)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ if (cchDest == 1)
+ {
+ *pszDestEnd = L'\0';
+ }
+
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ else
+ {
+ wchar_t ch;
+
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ while ((cchRemaining > 1) && (ch = (wchar_t)getwc(stdin)) != L'\n')
+ {
+ if (ch == EOF)
+ {
+ if (pszDestEnd == pszDest)
+ {
+ // we failed to read anything from stdin
+ hr = STRSAFE_E_END_OF_FILE;
+ }
+ break;
+ }
+
+ *pszDestEnd = ch;
+
+ pszDestEnd++;
+ cchRemaining--;
+ }
+
+ if (cchRemaining > 0)
+ {
+ // there is extra room
+ if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
+ {
+ memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
+ }
+ }
+
+ *pszDestEnd = L'\0';
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+
+ if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) ||
+ (hr == STRSAFE_E_INSUFFICIENT_BUFFER) ||
+ (hr == STRSAFE_E_END_OF_FILE))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+#endif // !STRSAFE_LIB_IMPL
+
+
+// Do not call these functions, they are worker functions for internal use within this file
+#ifdef DEPRECATE_SUPPORTED
+#pragma deprecated(StringCopyWorkerA)
+#pragma deprecated(StringCopyWorkerW)
+#pragma deprecated(StringCopyExWorkerA)
+#pragma deprecated(StringCopyExWorkerW)
+#pragma deprecated(StringCatWorkerA)
+#pragma deprecated(StringCatWorkerW)
+#pragma deprecated(StringCatExWorkerA)
+#pragma deprecated(StringCatExWorkerW)
+#pragma deprecated(StringCatNWorkerA)
+#pragma deprecated(StringCatNWorkerW)
+#pragma deprecated(StringCatNExWorkerA)
+#pragma deprecated(StringCatNExWorkerW)
+#pragma deprecated(StringVPrintfWorkerA)
+#pragma deprecated(StringVPrintfWorkerW)
+#pragma deprecated(StringVPrintfExWorkerA)
+#pragma deprecated(StringVPrintfExWorkerW)
+#pragma deprecated(StringLengthWorkerA)
+#pragma deprecated(StringLengthWorkerW)
+#else
+#define StringCopyWorkerA StringCopyWorkerA_instead_use_StringCchCopyA_or_StringCchCopyExA;
+#define StringCopyWorkerW StringCopyWorkerW_instead_use_StringCchCopyW_or_StringCchCopyExW;
+#define StringCopyExWorkerA StringCopyExWorkerA_instead_use_StringCchCopyA_or_StringCchCopyExA;
+#define StringCopyExWorkerW StringCopyExWorkerW_instead_use_StringCchCopyW_or_StringCchCopyExW;
+#define StringCatWorkerA StringCatWorkerA_instead_use_StringCchCatA_or_StringCchCatExA;
+#define StringCatWorkerW StringCatWorkerW_instead_use_StringCchCatW_or_StringCchCatExW;
+#define StringCatExWorkerA StringCatExWorkerA_instead_use_StringCchCatA_or_StringCchCatExA;
+#define StringCatExWorkerW StringCatExWorkerW_instead_use_StringCchCatW_or_StringCchCatExW;
+#define StringCatNWorkerA StringCatNWorkerA_instead_use_StringCchCatNA_or_StrincCbCatNA;
+#define StringCatNWorkerW StringCatNWorkerW_instead_use_StringCchCatNW_or_StringCbCatNW;
+#define StringCatNExWorkerA StringCatNExWorkerA_instead_use_StringCchCatNExA_or_StringCbCatNExA;
+#define StringCatNExWorkerW StringCatNExWorkerW_instead_use_StringCchCatNExW_or_StringCbCatNExW;
+#define StringVPrintfWorkerA StringVPrintfWorkerA_instead_use_StringCchVPrintfA_or_StringCchVPrintfExA;
+#define StringVPrintfWorkerW StringVPrintfWorkerW_instead_use_StringCchVPrintfW_or_StringCchVPrintfExW;
+#define StringVPrintfExWorkerA StringVPrintfExWorkerA_instead_use_StringCchVPrintfA_or_StringCchVPrintfExA;
+#define StringVPrintfExWorkerW StringVPrintfExWorkerW_instead_use_StringCchVPrintfW_or_StringCchVPrintfExW;
+#define StringLengthWorkerA StringLengthWorkerA_instead_use_StringCchLengthA_or_StringCbLengthA;
+#define StringLengthWorkerW StringLengthWorkerW_instead_use_StringCchLengthW_or_StringCbLengthW;
+#endif // !DEPRECATE_SUPPORTED
+
+
+#ifndef STRSAFE_NO_DEPRECATE
+// Deprecate all of the unsafe functions to generate compiletime errors. If you do not want
+// this then you can #define STRSAFE_NO_DEPRECATE before including this file.
+#ifdef DEPRECATE_SUPPORTED
+
+// First all the names that are a/w variants (or shouldn't be #defined by now anyway).
+#pragma deprecated(lstrcpyA)
+#pragma deprecated(lstrcpyW)
+#pragma deprecated(lstrcatA)
+#pragma deprecated(lstrcatW)
+#pragma deprecated(wsprintfA)
+#pragma deprecated(wsprintfW)
+
+#pragma deprecated(StrCpyW)
+#pragma deprecated(StrCatW)
+#pragma deprecated(StrNCatA)
+#pragma deprecated(StrNCatW)
+#pragma deprecated(StrCatNA)
+#pragma deprecated(StrCatNW)
+#pragma deprecated(wvsprintfA)
+#pragma deprecated(wvsprintfW)
+
+#pragma deprecated(strcpy)
+#pragma deprecated(wcscpy)
+#pragma deprecated(strcat)
+#pragma deprecated(wcscat)
+#pragma deprecated(sprintf)
+#pragma deprecated(swprintf)
+#pragma deprecated(vsprintf)
+#pragma deprecated(vswprintf)
+#pragma deprecated(_snprintf)
+#pragma deprecated(_snwprintf)
+#pragma deprecated(_vsnprintf)
+#pragma deprecated(_vsnwprintf)
+#pragma deprecated(gets)
+#pragma deprecated(_getws)
+
+// Then all the windows.h names - we need to undef and redef based on UNICODE setting
+#undef lstrcpy
+#undef lstrcat
+#undef wsprintf
+#undef wvsprintf
+#pragma deprecated(lstrcpy)
+#pragma deprecated(lstrcat)
+#pragma deprecated(wsprintf)
+#pragma deprecated(wvsprintf)
+#ifdef UNICODE
+#define lstrcpy lstrcpyW
+#define lstrcat lstrcatW
+#define wsprintf wsprintfW
+#define wvsprintf wvsprintfW
+#else
+#define lstrcpy lstrcpyA
+#define lstrcat lstrcatA
+#define wsprintf wsprintfA
+#define wvsprintf wvsprintfA
+#endif
+
+// Then the shlwapi names - they key off UNICODE also.
+#undef StrCpyA
+#undef StrCpy
+#undef StrCatA
+#undef StrCat
+#undef StrNCat
+#undef StrCatN
+#pragma deprecated(StrCpyA)
+#pragma deprecated(StrCatA)
+#pragma deprecated(StrCatN)
+#pragma deprecated(StrCpy)
+#pragma deprecated(StrCat)
+#pragma deprecated(StrNCat)
+#define StrCpyA lstrcpyA
+#define StrCatA lstrcatA
+#define StrCatN StrNCat
+#ifdef UNICODE
+#define StrCpy StrCpyW
+#define StrCat StrCatW
+#define StrNCat StrNCatW
+#else
+#define StrCpy lstrcpyA
+#define StrCat lstrcatA
+#define StrNCat StrNCatA
+#endif
+
+// Then all the CRT names - we need to undef/redef based on _UNICODE value.
+#undef _tcscpy
+#undef _ftcscpy
+#undef _tcscat
+#undef _ftcscat
+#undef _stprintf
+#undef _sntprintf
+#undef _vstprintf
+#undef _vsntprintf
+#undef _getts
+#pragma deprecated(_tcscpy)
+#pragma deprecated(_ftcscpy)
+#pragma deprecated(_tcscat)
+#pragma deprecated(_ftcscat)
+#pragma deprecated(_stprintf)
+#pragma deprecated(_sntprintf)
+#pragma deprecated(_vstprintf)
+#pragma deprecated(_vsntprintf)
+#pragma deprecated(_getts)
+#ifdef _UNICODE
+#define _tcscpy wcscpy
+#define _ftcscpy wcscpy
+#define _tcscat wcscat
+#define _ftcscat wcscat
+#define _stprintf swprintf
+#define _sntprintf _snwprintf
+#define _vstprintf vswprintf
+#define _vsntprintf _vsnwprintf
+#define _getts _getws
+#else
+#define _tcscpy strcpy
+#define _ftcscpy strcpy
+#define _tcscat strcat
+#define _ftcscat strcat
+#define _stprintf sprintf
+#define _sntprintf _snprintf
+#define _vstprintf vsprintf
+#define _vsntprintf _vsnprintf
+#define _getts gets
+#endif
+
+#else // DEPRECATE_SUPPORTED
+
+#undef strcpy
+#define strcpy strcpy_instead_use_StringCbCopyA_or_StringCchCopyA;
+
+#undef wcscpy
+#define wcscpy wcscpy_instead_use_StringCbCopyW_or_StringCchCopyW;
+
+#undef strcat
+#define strcat strcat_instead_use_StringCbCatA_or_StringCchCatA;
+
+#undef wcscat
+#define wcscat wcscat_instead_use_StringCbCatW_or_StringCchCatW;
+
+#undef sprintf
+#define sprintf sprintf_instead_use_StringCbPrintfA_or_StringCchPrintfA;
+
+#undef swprintf
+#define swprintf swprintf_instead_use_StringCbPrintfW_or_StringCchPrintfW;
+
+#undef vsprintf
+#define vsprintf vsprintf_instead_use_StringCbVPrintfA_or_StringCchVPrintfA;
+
+#undef vswprintf
+#define vswprintf vswprintf_instead_use_StringCbVPrintfW_or_StringCchVPrintfW;
+
+#undef _snprintf
+#define _snprintf _snprintf_instead_use_StringCbPrintfA_or_StringCchPrintfA;
+
+#undef _snwprintf
+#define _snwprintf _snwprintf_instead_use_StringCbPrintfW_or_StringCchPrintfW;
+
+#undef _vsnprintf
+#define _vsnprintf _vsnprintf_instead_use_StringCbVPrintfA_or_StringCchVPrintfA;
+
+#undef _vsnwprintf
+#define _vsnwprintf _vsnwprintf_instead_use_StringCbVPrintfW_or_StringCchVPrintfW;
+
+#undef strcpyA
+#define strcpyA strcpyA_instead_use_StringCbCopyA_or_StringCchCopyA;
+
+#undef strcpyW
+#define strcpyW strcpyW_instead_use_StringCbCopyW_or_StringCchCopyW;
+
+#undef lstrcpy
+#define lstrcpy lstrcpy_instead_use_StringCbCopy_or_StringCchCopy;
+
+#undef lstrcpyA
+#define lstrcpyA lstrcpyA_instead_use_StringCbCopyA_or_StringCchCopyA;
+
+#undef lstrcpyW
+#define lstrcpyW lstrcpyW_instead_use_StringCbCopyW_or_StringCchCopyW;
+
+#undef StrCpy
+#define StrCpy StrCpy_instead_use_StringCbCopy_or_StringCchCopy;
+
+#undef StrCpyA
+#define StrCpyA StrCpyA_instead_use_StringCbCopyA_or_StringCchCopyA;
+
+#undef StrCpyW
+#define StrCpyW StrCpyW_instead_use_StringCbCopyW_or_StringCchCopyW;
+
+#undef _tcscpy
+#define _tcscpy _tcscpy_instead_use_StringCbCopy_or_StringCchCopy;
+
+#undef _ftcscpy
+#define _ftcscpy _ftcscpy_instead_use_StringCbCopy_or_StringCchCopy;
+
+#undef lstrcat
+#define lstrcat lstrcat_instead_use_StringCbCat_or_StringCchCat;
+
+#undef lstrcatA
+#define lstrcatA lstrcatA_instead_use_StringCbCatA_or_StringCchCatA;
+
+#undef lstrcatW
+#define lstrcatW lstrcatW_instead_use_StringCbCatW_or_StringCchCatW;
+
+#undef StrCat
+#define StrCat StrCat_instead_use_StringCbCat_or_StringCchCat;
+
+#undef StrCatA
+#define StrCatA StrCatA_instead_use_StringCbCatA_or_StringCchCatA;
+
+#undef StrCatW
+#define StrCatW StrCatW_instead_use_StringCbCatW_or_StringCchCatW;
+
+#undef StrNCat
+#define StrNCat StrNCat_instead_use_StringCbCatN_or_StringCchCatN;
+
+#undef StrNCatA
+#define StrNCatA StrNCatA_instead_use_StringCbCatNA_or_StringCchCatNA;
+
+#undef StrNCatW
+#define StrNCatW StrNCatW_instead_use_StringCbCatNW_or_StringCchCatNW;
+
+#undef StrCatN
+#define StrCatN StrCatN_instead_use_StringCbCatN_or_StringCchCatN;
+
+#undef StrCatNA
+#define StrCatNA StrCatNA_instead_use_StringCbCatNA_or_StringCchCatNA;
+
+#undef StrCatNW
+#define StrCatNW StrCatNW_instead_use_StringCbCatNW_or_StringCchCatNW;
+
+#undef _tcscat
+#define _tcscat _tcscat_instead_use_StringCbCat_or_StringCchCat;
+
+#undef _ftcscat
+#define _ftcscat _ftcscat_instead_use_StringCbCat_or_StringCchCat;
+
+#undef wsprintf
+#define wsprintf wsprintf_instead_use_StringCbPrintf_or_StringCchPrintf;
+
+#undef wsprintfA
+#define wsprintfA wsprintfA_instead_use_StringCbPrintfA_or_StringCchPrintfA;
+
+#undef wsprintfW
+#define wsprintfW wsprintfW_instead_use_StringCbPrintfW_or_StringCchPrintfW;
+
+#undef wvsprintf
+#define wvsprintf wvsprintf_instead_use_StringCbVPrintf_or_StringCchVPrintf;
+
+#undef wvsprintfA
+#define wvsprintfA wvsprintfA_instead_use_StringCbVPrintfA_or_StringCchVPrintfA;
+
+#undef wvsprintfW
+#define wvsprintfW wvsprintfW_instead_use_StringCbVPrintfW_or_StringCchVPrintfW;
+
+#undef _vstprintf
+#define _vstprintf _vstprintf_instead_use_StringCbVPrintf_or_StringCchVPrintf;
+
+#undef _vsntprintf
+#define _vsntprintf _vsntprintf_instead_use_StringCbVPrintf_or_StringCchVPrintf;
+
+#undef _stprintf
+#define _stprintf _stprintf_instead_use_StringCbPrintf_or_StringCchPrintf;
+
+#undef _sntprintf
+#define _sntprintf _sntprintf_instead_use_StringCbPrintf_or_StringCchPrintf;
+
+#undef _getts
+#define _getts _getts_instead_use_StringCbGets_or_StringCchGets;
+
+#undef gets
+#define gets _gets_instead_use_StringCbGetsA_or_StringCchGetsA;
+
+#undef _getws
+#define _getws _getws_instead_use_StringCbGetsW_or_StringCchGetsW;
+
+#endif // !DEPRECATE_SUPPORTED
+#endif // !STRSAFE_NO_DEPRECATE
+
+#ifdef _NTSTRSAFE_H_INCLUDED_
+#pragma warning(pop)
+#endif // _NTSTRSAFE_H_INCLUDED_
+
+#endif // _STRSAFE_H_INCLUDED_
diff --git a/cpp/pipe/src/pipe.c b/cpp/pipe/src/pipe.c
new file mode 100644
index 0000000..c83c76d
--- /dev/null
+++ b/cpp/pipe/src/pipe.c
@@ -0,0 +1,262 @@
+#include
+#include
+#include
+#include "pipe.h"
+
+#define DEBUG 0
+
+JNIEXPORT jint JNICALL Java_pipe_Pipes_CreateNamedPipe
+(
+ JNIEnv *env,
+ jclass className,
+ jstring sPipeName,
+ jint dwOpenMode,
+ jint dwPipeMode,
+ jint nMaxInstances,
+ jint nOutBufferSize,
+ jint nInBufferSize,
+ jint nDefaultTimeOut,
+ jint lpSecurityAttributes
+ )
+{
+ HANDLE pipeHandler;
+ LPCSTR pipeName;
+ pipeName = (*env)->GetStringUTFChars(env, sPipeName, NULL);
+ if (pipeName == NULL)
+ return -1;
+
+ if (DEBUG)
+ {
+ printf("Native: Pipe Name %s\n", pipeName);
+ printf("Native: dwOpenMode %d\n", dwOpenMode);
+ printf("Native: dwPipeMode %d\n", dwPipeMode);
+ printf("Native: nMaxInstances %d\n", nMaxInstances);
+ printf("Native: nOutBufferSize %d\n", nOutBufferSize);
+ printf("Native: nInBufferSize %d\n", nInBufferSize);
+ printf("Native: nDefaultTimeOut %d\n", nDefaultTimeOut);
+ }
+
+ pipeHandler = CreateNamedPipe((LPCSTR)pipeName, dwOpenMode, dwPipeMode, nMaxInstances, nOutBufferSize, nInBufferSize,
+ nDefaultTimeOut, (LPSECURITY_ATTRIBUTES) lpSecurityAttributes);
+
+ (*env)->ReleaseStringUTFChars(env, sPipeName, pipeName);
+ return (jint) pipeHandler;
+}
+
+JNIEXPORT jboolean JNICALL Java_pipe_Pipes_ConnectNamedPipe
+(
+ JNIEnv *env,
+ jclass className,
+ jint hNamedPipe,
+ jint lpOverlapped
+ )
+{
+ BOOL fConnected;
+ HANDLE pipeHandler = (HANDLE) hNamedPipe;
+ fConnected = ConnectNamedPipe(pipeHandler, (LPOVERLAPPED) lpOverlapped);
+ return fConnected;
+}
+
+JNIEXPORT jint JNICALL Java_pipe_Pipes_GetLastError
+(
+ JNIEnv *env,
+ jclass className
+ )
+{
+ DWORD errorNumber = GetLastError();
+ return (jint) errorNumber;
+}
+
+JNIEXPORT jboolean JNICALL Java_pipe_Pipes_CloseHandle
+(
+ JNIEnv *env,
+ jclass className,
+ jint hNamedPipe
+ )
+{
+ BOOL result;
+ HANDLE pipeHandler = (HANDLE) hNamedPipe;
+ result = CloseHandle(pipeHandler);
+ return result;
+}
+
+JNIEXPORT jbyteArray JNICALL Java_pipe_Pipes_ReadFile
+(
+ JNIEnv *env,
+ jclass className,
+ jint hNamedPipe,
+ jint nNumberOfBytesToRead
+ )
+{
+ int bytesRead = 0;
+ BOOL result;
+ HANDLE pipeHandler = (HANDLE) hNamedPipe;
+ LPVOID buffer;
+ jbyteArray lpBuffer;
+
+ buffer = (LPVOID)LocalAlloc(LMEM_ZEROINIT, nNumberOfBytesToRead);
+
+ if (DEBUG)
+ {
+ printf("Native: Before ReadFile pipeHandler %d nNumberOfBytesToRead %d\n", pipeHandler, nNumberOfBytesToRead);
+ }
+ result = ReadFile(pipeHandler, (LPVOID) buffer, (DWORD) nNumberOfBytesToRead, &bytesRead, (LPOVERLAPPED) 0);
+ if (result)
+ {
+ lpBuffer = (*env)->NewByteArray(env, (jsize) bytesRead);
+ (*env)->SetByteArrayRegion(env, lpBuffer, 0, (jsize) bytesRead, (jbyte *) buffer);
+ } else
+ bytesRead = 0;
+
+ LocalFree(buffer);
+
+ if (DEBUG)
+ {
+ printf("Native: After ReadFile BytesRead %d\n", bytesRead);
+ }
+ return lpBuffer;
+}
+
+JNIEXPORT jint JNICALL Java_pipe_Pipes_WriteFile
+(
+ JNIEnv *env,
+ jclass className,
+ jint hNamedPipe,
+ jbyteArray lpBuffer,
+ jint nNumberOfBytesToWrite
+ )
+{
+ int bytesWritten = 0;
+ BOOL result;
+ HANDLE pipeHandler = (HANDLE) hNamedPipe;
+ LPVOID buffer;
+
+ buffer = (LPVOID)LocalAlloc(LMEM_ZEROINIT, nNumberOfBytesToWrite);
+
+ (*env)->GetByteArrayRegion(env, lpBuffer, 0, nNumberOfBytesToWrite, buffer);
+ result = WriteFile(pipeHandler, buffer, (DWORD) nNumberOfBytesToWrite, (LPDWORD) &bytesWritten, (LPOVERLAPPED) 0);
+ LocalFree(buffer);
+
+ if (DEBUG)
+ {
+ printf("Native: After WriteFile BytesReadWritten %d\n", bytesWritten);
+ }
+
+ if (!result)
+ {
+ if (GetLastError() != ERROR_IO_PENDING)
+ result = 0;
+ else
+ result = 1;
+ }
+ if (!result)
+ {
+ bytesWritten = -1;
+ }
+ return bytesWritten;
+}
+
+JNIEXPORT jboolean JNICALL Java_pipe_Pipes_FlushFileBuffers
+(
+ JNIEnv *env,
+ jclass className,
+ jint hNamedPipe
+ )
+{
+ BOOL result;
+ HANDLE pipeHandler = (HANDLE) hNamedPipe;
+ result = FlushFileBuffers(pipeHandler);
+ return result;
+}
+
+JNIEXPORT jboolean JNICALL Java_pipe_Pipes_DisconnectNamedPipe
+(
+ JNIEnv *env,
+ jclass className,
+ jint hNamedPipe
+ )
+{
+ BOOL result;
+ HANDLE pipeHandler = (HANDLE) hNamedPipe;
+ result = DisconnectNamedPipe(pipeHandler);
+ return result;
+}
+
+JNIEXPORT jint JNICALL Java_pipe_Pipes_CreateFile
+(
+ JNIEnv *env,
+ jclass className,
+ jstring lpFileName,
+ jint dwDesiredAccess,
+ jint dwShareMode,
+ jint lpSecurityAttributes,
+ jint dwCreationDisposition,
+ jint dwFlagsAndAttributes,
+ jint hTemplateFile
+ )
+{
+ HANDLE pipeHandler;
+ const jbyte *fileName;
+ fileName = (*env)->GetStringUTFChars(env, lpFileName, NULL);
+ if (fileName == NULL)
+ return -1;
+ pipeHandler = CreateFile((LPCSTR) fileName, (DWORD) dwDesiredAccess, (DWORD) dwShareMode,
+ (LPSECURITY_ATTRIBUTES) lpSecurityAttributes, (DWORD) dwCreationDisposition, (DWORD) dwFlagsAndAttributes, (HANDLE) hTemplateFile);
+ return (jint) pipeHandler;
+}
+
+JNIEXPORT jboolean JNICALL Java_pipe_Pipes_WaitNamedPipe
+(
+ JNIEnv *env,
+ jclass className,
+ jstring lpNamedPipeName,
+ jint nTimeOut
+ )
+{
+ BOOL result;
+ const jbyte *pipeName;
+ pipeName = (*env)->GetStringUTFChars(env, lpNamedPipeName, NULL);
+ if (pipeName == NULL)
+ return 0;
+ result = WaitNamedPipe((LPCSTR) pipeName, (DWORD) nTimeOut);
+ return result;
+}
+
+JNIEXPORT jstring JNICALL Java_pipe_Pipes_FormatMessage
+(
+ JNIEnv *env,
+ jclass className,
+ jint errorCode
+)
+{
+ LPVOID lpMsgBuf;
+ LPVOID lpDisplayBuf;
+ DWORD dw = (DWORD) errorCode;
+
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ dw,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf,
+ 0, NULL );
+
+ lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
+ (lstrlen((LPCTSTR)lpMsgBuf) + 40) * sizeof(TCHAR));
+ StringCchPrintf((LPTSTR)lpDisplayBuf, LocalSize(lpDisplayBuf) / sizeof(TCHAR),
+ TEXT("Failed with error %d: %s"), dw, lpMsgBuf);
+ return (jstring) (*env)->NewStringUTF(env, lpDisplayBuf);
+}
+
+JNIEXPORT void JNICALL Java_pipe_Pipes_Print(JNIEnv *env, jclass className, jstring lpMsgBuf)
+{
+ const jbyte *str;
+ str = (*env)->GetStringUTFChars(env, lpMsgBuf, NULL);
+ if (str == NULL)
+ return;
+ printf("Native: %s\n", str);
+ (*env)->ReleaseStringUTFChars(env, lpMsgBuf, str);
+ return;
+}
diff --git a/cpp/pipe/src/pipe.h b/cpp/pipe/src/pipe.h
new file mode 100644
index 0000000..4687162
--- /dev/null
+++ b/cpp/pipe/src/pipe.h
@@ -0,0 +1,109 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include
+/* Header for class Pipes */
+
+#ifndef _Included_pipe
+#define _Included_pipe
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: Pipes
+ * Method: CreateNamedPipe
+ * Signature: (Ljava/lang/String;IIIIIII)I
+ */
+JNIEXPORT jint JNICALL Java_pipe_Pipes_CreateNamedPipe
+ (JNIEnv *, jclass, jstring, jint, jint, jint, jint, jint, jint, jint);
+
+/*
+ * Class: Pipes
+ * Method: ConnectNamedPipe
+ * Signature: (II)Z
+ */
+JNIEXPORT jboolean JNICALL Java_pipe_Pipes_ConnectNamedPipe
+ (JNIEnv *, jclass, jint, jint);
+
+/*
+ * Class: Pipes
+ * Method: GetLastError
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_pipe_Pipes_GetLastError
+ (JNIEnv *, jclass);
+
+/*
+ * Class: Pipes
+ * Method: CloseHandle
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_pipe_Pipes_CloseHandle
+ (JNIEnv *, jclass, jint);
+
+/*
+ * Class: Pipes
+ * Method: ReadFile
+ * Signature: (II)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_pipe_Pipes_ReadFile
+ (JNIEnv *, jclass, jint, jint);
+
+/*
+ * Class: Pipes
+ * Method: WriteFile
+ * Signature: (I[BI)I
+ */
+JNIEXPORT jint JNICALL Java_pipe_Pipes_WriteFile
+ (JNIEnv *, jclass, jint, jbyteArray, jint);
+
+/*
+ * Class: Pipes
+ * Method: FlushFileBuffers
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_pipe_Pipes_FlushFileBuffers
+ (JNIEnv *, jclass, jint);
+
+/*
+ * Class: Pipes
+ * Method: DisconnectNamedPipe
+ * Signature: (I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_pipe_Pipes_DisconnectNamedPipe
+ (JNIEnv *, jclass, jint);
+
+/*
+ * Class: Pipes
+ * Method: CreateFile
+ * Signature: (Ljava/lang/String;IIIIII)I
+ */
+JNIEXPORT jint JNICALL Java_pipe_Pipes_CreateFile
+ (JNIEnv *, jclass, jstring, jint, jint, jint, jint, jint, jint);
+
+/*
+ * Class: Pipes
+ * Method: WaitNamedPipe
+ * Signature: (Ljava/lang/String;I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_pipe_Pipes_WaitNamedPipe
+ (JNIEnv *, jclass, jstring, jint);
+
+/*
+ * Class: Pipes
+ * Method: FormatMessage
+ * Signature: (I)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_pipe_Pipes_FormatMessage
+ (JNIEnv *, jclass, jint);
+
+/*
+ * Class: Pipes
+ * Method: Print
+ * Signature: (Ljava/lang/String;)V
+ */
+JNIEXPORT void JNICALL Java_pipe_Pipes_Print
+ (JNIEnv *, jclass, jstring);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/.classpath b/java/.classpath
similarity index 100%
rename from .classpath
rename to java/.classpath
diff --git a/java/.gitignore b/java/.gitignore
new file mode 100644
index 0000000..a4bf388
--- /dev/null
+++ b/java/.gitignore
@@ -0,0 +1,3 @@
+/bin
+/.settings
+/sound
diff --git a/.project b/java/.project
similarity index 100%
rename from .project
rename to java/.project
diff --git a/build.xml b/java/build.xml
similarity index 100%
rename from build.xml
rename to java/build.xml
diff --git a/lame.exe b/java/lame.exe
similarity index 100%
rename from lame.exe
rename to java/lame.exe
diff --git a/launch4j.xml b/java/launch4j.xml
similarity index 100%
rename from launch4j.xml
rename to java/launch4j.xml
diff --git a/lib/commons-cli-1.2.jar b/java/lib/commons-cli-1.2.jar
similarity index 100%
rename from lib/commons-cli-1.2.jar
rename to java/lib/commons-cli-1.2.jar
diff --git a/lib/commons-io-2.4.jar b/java/lib/commons-io-2.4.jar
similarity index 100%
rename from lib/commons-io-2.4.jar
rename to java/lib/commons-io-2.4.jar
diff --git a/lib/jid3lib-0.5.4.jar b/java/lib/jid3lib-0.5.4.jar
similarity index 100%
rename from lib/jid3lib-0.5.4.jar
rename to java/lib/jid3lib-0.5.4.jar
diff --git a/lib/jl1.0.1.jar b/java/lib/jl1.0.1.jar
similarity index 100%
rename from lib/jl1.0.1.jar
rename to java/lib/jl1.0.1.jar
diff --git a/lib/ostermillerutils-1.08.01.jar b/java/lib/ostermillerutils-1.08.01.jar
similarity index 100%
rename from lib/ostermillerutils-1.08.01.jar
rename to java/lib/ostermillerutils-1.08.01.jar
diff --git a/libgomp-1.dll b/java/libgomp-1.dll
similarity index 100%
rename from libgomp-1.dll
rename to java/libgomp-1.dll
diff --git a/libmad.dll b/java/libmad.dll
similarity index 100%
rename from libmad.dll
rename to java/libmad.dll
diff --git a/libmp3lame.dll b/java/libmp3lame.dll
similarity index 100%
rename from libmp3lame.dll
rename to java/libmp3lame.dll
diff --git a/pipes.dll b/java/pipes.dll
similarity index 100%
rename from pipes.dll
rename to java/pipes.dll
diff --git a/play.exe b/java/play.exe
similarity index 100%
rename from play.exe
rename to java/play.exe
diff --git a/pthreadgc2.dll b/java/pthreadgc2.dll
similarity index 100%
rename from pthreadgc2.dll
rename to java/pthreadgc2.dll
diff --git a/sox.exe b/java/sox.exe
similarity index 100%
rename from sox.exe
rename to java/sox.exe
diff --git a/soxi.exe b/java/soxi.exe
similarity index 100%
rename from soxi.exe
rename to java/soxi.exe
diff --git a/src/old/Converter.java b/java/src/old/Converter.java
similarity index 100%
rename from src/old/Converter.java
rename to java/src/old/Converter.java
diff --git a/src/old/List.java b/java/src/old/List.java
similarity index 100%
rename from src/old/List.java
rename to java/src/old/List.java
diff --git a/src/old/Mp3.java b/java/src/old/Mp3.java
similarity index 100%
rename from src/old/Mp3.java
rename to java/src/old/Mp3.java
diff --git a/src/old/Utils.java b/java/src/old/Utils.java
similarity index 100%
rename from src/old/Utils.java
rename to java/src/old/Utils.java
diff --git a/src/sound/Consumer.java b/java/src/sound/Consumer.java
similarity index 100%
rename from src/sound/Consumer.java
rename to java/src/sound/Consumer.java
diff --git a/src/sound/Format.java b/java/src/sound/Format.java
similarity index 100%
rename from src/sound/Format.java
rename to java/src/sound/Format.java
diff --git a/src/sound/GreedyInputStream.java b/java/src/sound/GreedyInputStream.java
similarity index 100%
rename from src/sound/GreedyInputStream.java
rename to java/src/sound/GreedyInputStream.java
diff --git a/src/sound/Port.java b/java/src/sound/Port.java
similarity index 100%
rename from src/sound/Port.java
rename to java/src/sound/Port.java
diff --git a/src/sound/Producer.java b/java/src/sound/Producer.java
similarity index 100%
rename from src/sound/Producer.java
rename to java/src/sound/Producer.java
diff --git a/src/sound/Source.java b/java/src/sound/Source.java
similarity index 100%
rename from src/sound/Source.java
rename to java/src/sound/Source.java
diff --git a/src/sound/SoxBuilder.java b/java/src/sound/SoxBuilder.java
similarity index 100%
rename from src/sound/SoxBuilder.java
rename to java/src/sound/SoxBuilder.java
diff --git a/src/sound/Stream.java b/java/src/sound/Stream.java
similarity index 100%
rename from src/sound/Stream.java
rename to java/src/sound/Stream.java
diff --git a/src/sound/Target.java b/java/src/sound/Target.java
similarity index 100%
rename from src/sound/Target.java
rename to java/src/sound/Target.java
diff --git a/src/sound/Test.java b/java/src/sound/Test.java
similarity index 100%
rename from src/sound/Test.java
rename to java/src/sound/Test.java
diff --git a/src/sound/Tool.java b/java/src/sound/Tool.java
similarity index 100%
rename from src/sound/Tool.java
rename to java/src/sound/Tool.java
diff --git a/src/sound/Transducer.java b/java/src/sound/Transducer.java
similarity index 100%
rename from src/sound/Transducer.java
rename to java/src/sound/Transducer.java
diff --git a/src/test/SoundAudit.java b/java/src/test/SoundAudit.java
similarity index 100%
rename from src/test/SoundAudit.java
rename to java/src/test/SoundAudit.java
diff --git a/src/test/lines/Main.java b/java/src/test/lines/Main.java
similarity index 100%
rename from src/test/lines/Main.java
rename to java/src/test/lines/Main.java
diff --git a/src/test/lines/SourceLine.java b/java/src/test/lines/SourceLine.java
similarity index 100%
rename from src/test/lines/SourceLine.java
rename to java/src/test/lines/SourceLine.java
diff --git a/src/test/lines/TargetLine.java b/java/src/test/lines/TargetLine.java
similarity index 100%
rename from src/test/lines/TargetLine.java
rename to java/src/test/lines/TargetLine.java
diff --git a/stream.bat b/java/stream.bat
similarity index 100%
rename from stream.bat
rename to java/stream.bat
diff --git a/stream.exe b/java/stream.exe
similarity index 100%
rename from stream.exe
rename to java/stream.exe
diff --git a/stream.jar b/java/stream.jar
similarity index 100%
rename from stream.jar
rename to java/stream.jar
diff --git a/java/txt/keuze.txt b/java/txt/keuze.txt
new file mode 100644
index 0000000..7e9581d
--- /dev/null
+++ b/java/txt/keuze.txt
@@ -0,0 +1,13 @@
+from pcm:
+
+-r -s [--unsigned] [--big-endian]
+
+to mp3:
+--cbr -b
+
+
+mp3 to pcm:
+--decode
+
+always:
+ - - --quiet
\ No newline at end of file
diff --git a/java/txt/mp3 b/java/txt/mp3
new file mode 100644
index 0000000..daf87ab
--- /dev/null
+++ b/java/txt/mp3
@@ -0,0 +1,1357 @@
+C:/Users/Rik/Music/Artists/+44/When Your Heart Stops Beating/+44 - 155.mp3
+C:/Users/Rik/Music/Artists/+44/When Your Heart Stops Beating/+44 - Baby Come On.mp3
+C:/Users/Rik/Music/Artists/+44/When Your Heart Stops Beating/+44 - Chapter 13.mp3
+C:/Users/Rik/Music/Artists/+44/When Your Heart Stops Beating/+44 - Cliff Diving.mp3
+C:/Users/Rik/Music/Artists/+44/When Your Heart Stops Beating/+44 - Interlude.mp3
+C:/Users/Rik/Music/Artists/+44/When Your Heart Stops Beating/+44 - Lillian.mp3
+C:/Users/Rik/Music/Artists/+44/When Your Heart Stops Beating/+44 - Little Death.mp3
+C:/Users/Rik/Music/Artists/+44/When Your Heart Stops Beating/+44 - Lycanthrope.mp3
+C:/Users/Rik/Music/Artists/+44/When Your Heart Stops Beating/+44 - Make You Smile.mp3
+C:/Users/Rik/Music/Artists/+44/When Your Heart Stops Beating/+44 - No, It Isn't.mp3
+C:/Users/Rik/Music/Artists/+44/When Your Heart Stops Beating/+44 - Weatherman.mp3
+C:/Users/Rik/Music/Artists/+44/When Your Heart Stops Beating/+44 - When Your Heart Stops Beating.mp3
+C:/Users/Rik/Music/Artists/10 Years Feeding/Feeding the Wolves/10 Years - Chasing the Rapture.mp3
+C:/Users/Rik/Music/Artists/10 Years Feeding/Feeding the Wolves/10 Years - Dead In the Water.mp3
+C:/Users/Rik/Music/Artists/10 Years Feeding/Feeding the Wolves/10 Years - Fade Into the Dream.mp3
+C:/Users/Rik/Music/Artists/10 Years Feeding/Feeding the Wolves/10 Years - Fix Me.mp3
+C:/Users/Rik/Music/Artists/10 Years Feeding/Feeding the Wolves/10 Years - Now Is the Time.mp3
+C:/Users/Rik/Music/Artists/10 Years Feeding/Feeding the Wolves/10 Years - One More Day.mp3
+C:/Users/Rik/Music/Artists/10 Years Feeding/Feeding the Wolves/10 Years - The Wicked Ones.mp3
+C:/Users/Rik/Music/Artists/10 Years Feeding/Feeding the Wolves/10 Years - Waking Up the Ghost.mp3
+C:/Users/Rik/Music/Artists/30 Seconds To Mars/A Beautiful Lie/30 Seconds to Mars - A Beautiful Lie.mp3
+C:/Users/Rik/Music/Artists/30 Seconds To Mars/A Beautiful Lie/30 Seconds to Mars - Attack.mp3
+C:/Users/Rik/Music/Artists/30 Seconds To Mars/A Beautiful Lie/30 Seconds to Mars - Battle of One.mp3
+C:/Users/Rik/Music/Artists/30 Seconds To Mars/A Beautiful Lie/30 Seconds to Mars - From Yesterday.mp3
+C:/Users/Rik/Music/Artists/30 Seconds To Mars/A Beautiful Lie/30 Seconds to Mars - R-Evolve.mp3
+C:/Users/Rik/Music/Artists/30 Seconds To Mars/A Beautiful Lie/30 Seconds to Mars - Savior.mp3
+C:/Users/Rik/Music/Artists/30 Seconds To Mars/A Beautiful Lie/30 Seconds to Mars - The Fantasy.mp3
+C:/Users/Rik/Music/Artists/30 Seconds To Mars/A Beautiful Lie/30 Seconds to Mars - Was It a Dream.mp3
+C:/Users/Rik/Music/Artists/30 Seconds To Mars/This Is War/30 Seconds to Mars - A Call to Arms.mp3
+C:/Users/Rik/Music/Artists/30 Seconds To Mars/This Is War/30 Seconds to Mars - Closer to the Edge.mp3
+C:/Users/Rik/Music/Artists/30 Seconds To Mars/This Is War/30 Seconds to Mars - Equinox.mp3
+C:/Users/Rik/Music/Artists/30 Seconds To Mars/This Is War/30 Seconds to Mars - Escape.mp3
+C:/Users/Rik/Music/Artists/30 Seconds To Mars/This Is War/30 Seconds to Mars - Hurricane.mp3
+C:/Users/Rik/Music/Artists/30 Seconds To Mars/This Is War/30 Seconds to Mars - Kings and Queens.mp3
+C:/Users/Rik/Music/Artists/30 Seconds To Mars/This Is War/30 Seconds to Mars - Night of the Hunter (Flood Remix).mp3
+C:/Users/Rik/Music/Artists/30 Seconds To Mars/This Is War/30 Seconds to Mars - Night of the Hunter.mp3
+C:/Users/Rik/Music/Artists/30 Seconds To Mars/This Is War/30 Seconds to Mars - Search & Destroy.mp3
+C:/Users/Rik/Music/Artists/30 Seconds To Mars/This Is War/30 Seconds to Mars - This Is War.mp3
+C:/Users/Rik/Music/Artists/All Time Low/Nothing Personal/All Time Low - A Party Song (The Walk of Shame).mp3
+C:/Users/Rik/Music/Artists/All Time Low/Nothing Personal/All Time Low - Break Your Little Heart.mp3
+C:/Users/Rik/Music/Artists/All Time Low/Nothing Personal/All Time Low - Damned If I Do Ya (Damned If I Don't).mp3
+C:/Users/Rik/Music/Artists/All Time Low/Nothing Personal/All Time Low - Hello Brooklyn.mp3
+C:/Users/Rik/Music/Artists/All Time Low/Nothing Personal/All Time Low - Keep the Change, You Filthy Animal.mp3
+C:/Users/Rik/Music/Artists/All Time Low/Nothing Personal/All Time Low - Lost In Stereo.mp3
+C:/Users/Rik/Music/Artists/All Time Low/Nothing Personal/All Time Low - Sick Little Games.mp3
+C:/Users/Rik/Music/Artists/All Time Low/Nothing Personal/All Time Low - Stella.mp3
+C:/Users/Rik/Music/Artists/All Time Low/Nothing Personal/All Time Low - Therapy.mp3
+C:/Users/Rik/Music/Artists/All Time Low/Nothing Personal/All Time Low - Too Much.mp3
+C:/Users/Rik/Music/Artists/All Time Low/Nothing Personal/All Time Low - Walls.mp3
+C:/Users/Rik/Music/Artists/All Time Low/Nothing Personal/All Time Low - Weightless.mp3
+C:/Users/Rik/Music/Artists/Anberlin/Dark Is The Way, Light Is A Place/Anberlin - Art of War.mp3
+C:/Users/Rik/Music/Artists/Anberlin/Dark Is The Way, Light Is A Place/Anberlin - Closer.mp3
+C:/Users/Rik/Music/Artists/Anberlin/Dark Is The Way, Light Is A Place/Anberlin - Depraved.mp3
+C:/Users/Rik/Music/Artists/Anberlin/Dark Is The Way, Light Is A Place/Anberlin - Down.mp3
+C:/Users/Rik/Music/Artists/Anberlin/Dark Is The Way, Light Is A Place/Anberlin - Impossible.mp3
+C:/Users/Rik/Music/Artists/Anberlin/Dark Is The Way, Light Is A Place/Anberlin - Pray Tell.mp3
+C:/Users/Rik/Music/Artists/Anberlin/Dark Is The Way, Light Is A Place/Anberlin - Take Me (As You Found Me).mp3
+C:/Users/Rik/Music/Artists/Anberlin/Dark Is The Way, Light Is A Place/Anberlin - To the Wolves.mp3
+C:/Users/Rik/Music/Artists/Anberlin/Dark Is The Way, Light Is A Place/Anberlin - We Owe This to Ourselves.mp3
+C:/Users/Rik/Music/Artists/Anberlin/Dark Is The Way, Light Is A Place/Anberlin - You Belong Here.mp3
+C:/Users/Rik/Music/Artists/Angels & Airwaves/Love/Angels & Airwaves - Clever Love.mp3
+C:/Users/Rik/Music/Artists/Angels & Airwaves/Love/Angels & Airwaves - Epic Holiday.mp3
+C:/Users/Rik/Music/Artists/Angels & Airwaves/Love/Angels & Airwaves - Et Ducit Mundum Per Luce.mp3
+C:/Users/Rik/Music/Artists/Angels & Airwaves/Love/Angels & Airwaves - Hallucinations.mp3
+C:/Users/Rik/Music/Artists/Angels & Airwaves/Love/Angels & Airwaves - Letters to God, Part Ii.mp3
+C:/Users/Rik/Music/Artists/Angels & Airwaves/Love/Angels & Airwaves - Shove.mp3
+C:/Users/Rik/Music/Artists/Angels & Airwaves/Love/Angels & Airwaves - Some Origins of Fire.mp3
+C:/Users/Rik/Music/Artists/Angels & Airwaves/Love/Angels & Airwaves - Soul Survivor (...2012).mp3
+C:/Users/Rik/Music/Artists/Angels & Airwaves/Love/Angels & Airwaves - The Flight of Apollo.mp3
+C:/Users/Rik/Music/Artists/Angels & Airwaves/Love/Angels & Airwaves - The Moon-Atomic (...Fragments and Fictions).mp3
+C:/Users/Rik/Music/Artists/Angels & Airwaves/Love/Angels & Airwaves - Young London.mp3
+C:/Users/Rik/Music/Artists/Arcade Fire/The Suburbs/Arcade Fire - City With No Children.mp3
+C:/Users/Rik/Music/Artists/Arcade Fire/The Suburbs/Arcade Fire - Empty Room.mp3
+C:/Users/Rik/Music/Artists/Arcade Fire/The Suburbs/Arcade Fire - Half Light Ii (No Celebration).mp3
+C:/Users/Rik/Music/Artists/Arcade Fire/The Suburbs/Arcade Fire - Modern Man.mp3
+C:/Users/Rik/Music/Artists/Arcade Fire/The Suburbs/Arcade Fire - Month of May.mp3
+C:/Users/Rik/Music/Artists/Arcade Fire/The Suburbs/Arcade Fire - Suburban War.mp3
+C:/Users/Rik/Music/Artists/Blink-182/Greatest Hits/Blink-182 - Adam's Song.mp3
+C:/Users/Rik/Music/Artists/Blink-182/Greatest Hits/Blink-182 - All the Small Things.mp3
+C:/Users/Rik/Music/Artists/Blink-182/Greatest Hits/Blink-182 - Always.mp3
+C:/Users/Rik/Music/Artists/Blink-182/Greatest Hits/Blink-182 - Another Girl Another Planet.mp3
+C:/Users/Rik/Music/Artists/Blink-182/Greatest Hits/Blink-182 - Carousel.mp3
+C:/Users/Rik/Music/Artists/Blink-182/Greatest Hits/Blink-182 - Dammit.mp3
+C:/Users/Rik/Music/Artists/Blink-182/Greatest Hits/Blink-182 - Down.mp3
+C:/Users/Rik/Music/Artists/Blink-182/Greatest Hits/Blink-182 - Feelin' This.mp3
+C:/Users/Rik/Music/Artists/Blink-182/Greatest Hits/Blink-182 - First Date.mp3
+C:/Users/Rik/Music/Artists/Blink-182/Greatest Hits/Blink-182 - Josie.mp3
+C:/Users/Rik/Music/Artists/Blink-182/Greatest Hits/Blink-182 - M&m's.mp3
+C:/Users/Rik/Music/Artists/Blink-182/Greatest Hits/Blink-182 - Man Overboard (Live).mp3
+C:/Users/Rik/Music/Artists/Blink-182/Greatest Hits/Blink-182 - Miss You.mp3
+C:/Users/Rik/Music/Artists/Blink-182/Greatest Hits/Blink-182 - Not Now.mp3
+C:/Users/Rik/Music/Artists/Blink-182/Greatest Hits/Blink-182 - Rock Show.mp3
+C:/Users/Rik/Music/Artists/Blink-182/Greatest Hits/Blink-182 - Stay Together For the Kids.mp3
+C:/Users/Rik/Music/Artists/Blink-182/Greatest Hits/Blink-182 - What's My Age Again.mp3
+C:/Users/Rik/Music/Artists/Coldplay/Coldplay - Clocks.mp3
+C:/Users/Rik/Music/Artists/Coldplay/Coldplay - In My Place.mp3
+C:/Users/Rik/Music/Artists/Coldplay/Coldplay - Life In Technicolor Ii.mp3
+C:/Users/Rik/Music/Artists/Coldplay/Coldplay - Speed of Sound.mp3
+C:/Users/Rik/Music/Artists/Coldplay/Coldplay - Talk.mp3
+C:/Users/Rik/Music/Artists/Coldplay/Viva la Vida or Death and All His Friends/Coldplay - Life In Technicolor.mp3
+C:/Users/Rik/Music/Artists/Coldplay/Viva la Vida or Death and All His Friends/Coldplay - Lost!.mp3
+C:/Users/Rik/Music/Artists/Coldplay/Viva la Vida or Death and All His Friends/Coldplay - Lovers In Japan Reign of Love.mp3
+C:/Users/Rik/Music/Artists/Coldplay/Viva la Vida or Death and All His Friends/Coldplay - Viva La Vida.mp3
+C:/Users/Rik/Music/Artists/Counting Crows/Counting Crows - Accidentally In Love.mp3
+C:/Users/Rik/Music/Artists/Counting Crows/Films About Ghosts - The Best Of/Counting Crows - American Girls.mp3
+C:/Users/Rik/Music/Artists/Counting Crows/Films About Ghosts - The Best Of/Counting Crows - Angels of the Silences.mp3
+C:/Users/Rik/Music/Artists/Counting Crows/Films About Ghosts - The Best Of/Counting Crows - Big Yellow Taxi.mp3
+C:/Users/Rik/Music/Artists/Counting Crows/Films About Ghosts - The Best Of/Counting Crows - Einstein On the Beach (For An Eggman).mp3
+C:/Users/Rik/Music/Artists/Counting Crows/Films About Ghosts - The Best Of/Counting Crows - Friend of the Devil.mp3
+C:/Users/Rik/Music/Artists/Counting Crows/Films About Ghosts - The Best Of/Counting Crows - Hanginaround.mp3
+C:/Users/Rik/Music/Artists/Counting Crows/Films About Ghosts - The Best Of/Counting Crows - Mr. Jones.mp3
+C:/Users/Rik/Music/Artists/Counting Crows/Films About Ghosts - The Best Of/Counting Crows - Mrs. Potter's Lullaby.mp3
+C:/Users/Rik/Music/Artists/Counting Crows/Films About Ghosts - The Best Of/Counting Crows - Omaha.mp3
+C:/Users/Rik/Music/Artists/Counting Crows/Films About Ghosts - The Best Of/Counting Crows - Rain King.mp3
+C:/Users/Rik/Music/Artists/Counting Crows/Films About Ghosts - The Best Of/Counting Crows - Recovering the Satellites.mp3
+C:/Users/Rik/Music/Artists/Counting Crows/Films About Ghosts - The Best Of/Counting Crows - She Don't Want Nobody Near.mp3
+C:/Users/Rik/Music/Artists/Destine/Lightspeed/Destine - Am I So Blind.mp3
+C:/Users/Rik/Music/Artists/Destine/Lightspeed/Destine - Burn.mp3
+C:/Users/Rik/Music/Artists/Destine/Lightspeed/Destine - California Summer.mp3
+C:/Users/Rik/Music/Artists/Destine/Lightspeed/Destine - Everything In Me.mp3
+C:/Users/Rik/Music/Artists/Destine/Lightspeed/Destine - Forget About Me.mp3
+C:/Users/Rik/Music/Artists/Destine/Lightspeed/Destine - In the End.mp3
+C:/Users/Rik/Music/Artists/Destine/Lightspeed/Destine - In Your Arms.mp3
+C:/Users/Rik/Music/Artists/Destine/Lightspeed/Destine - Sinking Sand.mp3
+C:/Users/Rik/Music/Artists/Destine/Lightspeed/Destine - Spiders.mp3
+C:/Users/Rik/Music/Artists/Destine/Lightspeed/Destine - Stars.mp3
+C:/Users/Rik/Music/Artists/Destine/Lightspeed/Destine - Wake Me.mp3
+C:/Users/Rik/Music/Artists/Destine/Lightspeed/Destine - Where Are You Now.mp3
+C:/Users/Rik/Music/Artists/Di-Rect/Di-Rect - Hungry For Love.mp3
+C:/Users/Rik/Music/Artists/Di-Rect/Di-Rect - She.mp3
+C:/Users/Rik/Music/Artists/Di-Rect/Di-Rect/Di-Rect - A Good Thing.mp3
+C:/Users/Rik/Music/Artists/Di-Rect/Di-Rect/Di-Rect - A Whole New Era.mp3
+C:/Users/Rik/Music/Artists/Di-Rect/Di-Rect/Di-Rect - Break Us In Two.mp3
+C:/Users/Rik/Music/Artists/Di-Rect/Di-Rect/Di-Rect - Bring Down Tomorrow.mp3
+C:/Users/Rik/Music/Artists/Di-Rect/Di-Rect/Di-Rect - Don't Look Back.mp3
+C:/Users/Rik/Music/Artists/Di-Rect/Di-Rect/Di-Rect - I Juct Can't Stand.mp3
+C:/Users/Rik/Music/Artists/Di-Rect/Di-Rect/Di-Rect - It Feels.mp3
+C:/Users/Rik/Music/Artists/Di-Rect/Di-Rect/Di-Rect - Johny.mp3
+C:/Users/Rik/Music/Artists/Di-Rect/Di-Rect/Di-Rect - Lucky.mp3
+C:/Users/Rik/Music/Artists/Di-Rect/Di-Rect/Di-Rect - One Step Closer.mp3
+C:/Users/Rik/Music/Artists/Di-Rect/Di-Rect/Di-Rect - Over and Over.mp3
+C:/Users/Rik/Music/Artists/Di-Rect/Di-Rect/Di-Rect - Someday.mp3
+C:/Users/Rik/Music/Artists/Dropout Year/Best Friends For Never/Dropout Year - A Coming of Age Story.mp3
+C:/Users/Rik/Music/Artists/Dropout Year/Best Friends For Never/Dropout Year - As You Wish.mp3
+C:/Users/Rik/Music/Artists/Dropout Year/Best Friends For Never/Dropout Year - Best Friends For Never.mp3
+C:/Users/Rik/Music/Artists/Dropout Year/Best Friends For Never/Dropout Year - Biggest Fan.mp3
+C:/Users/Rik/Music/Artists/Dropout Year/Best Friends For Never/Dropout Year - Confetti.mp3
+C:/Users/Rik/Music/Artists/Dropout Year/Best Friends For Never/Dropout Year - From Across the Room.mp3
+C:/Users/Rik/Music/Artists/Dropout Year/Best Friends For Never/Dropout Year - It Wasn't Over, It Still Isn't Over.mp3
+C:/Users/Rik/Music/Artists/Fall Out Boy/Folie A Deux/Fall Out Boy - (Coffee's For Closers).mp3
+C:/Users/Rik/Music/Artists/Fall Out Boy/Folie A Deux/Fall Out Boy - 20 Dollar Nose Bleed.mp3
+C:/Users/Rik/Music/Artists/Fall Out Boy/Folie A Deux/Fall Out Boy - 27.mp3
+C:/Users/Rik/Music/Artists/Fall Out Boy/Folie A Deux/Fall Out Boy - America's Suitehearts.mp3
+C:/Users/Rik/Music/Artists/Fall Out Boy/Folie A Deux/Fall Out Boy - Disloyal Order of Water Buffaloes.mp3
+C:/Users/Rik/Music/Artists/Fall Out Boy/Folie A Deux/Fall Out Boy - Headfirst Slide Into Coopestown On a Bad Bet.mp3
+C:/Users/Rik/Music/Artists/Fall Out Boy/Folie A Deux/Fall Out Boy - I Don't Care.mp3
+C:/Users/Rik/Music/Artists/Fall Out Boy/Folie A Deux/Fall Out Boy - She's My Winona.mp3
+C:/Users/Rik/Music/Artists/Fall Out Boy/Folie A Deux/Fall Out Boy - Tiffany Blews.mp3
+C:/Users/Rik/Music/Artists/Fall Out Boy/Folie A Deux/Fall Out Boy - West Coast Smoker.mp3
+C:/Users/Rik/Music/Artists/Fall Out Boy/Folie A Deux/Fall Out Boy - What a Catch, Donnie.mp3
+C:/Users/Rik/Music/Artists/Foo Fighters/Greatest Hits/Foo Fighters - All My Life.mp3
+C:/Users/Rik/Music/Artists/Foo Fighters/Greatest Hits/Foo Fighters - Best of You.mp3
+C:/Users/Rik/Music/Artists/Foo Fighters/Greatest Hits/Foo Fighters - Big Me.mp3
+C:/Users/Rik/Music/Artists/Foo Fighters/Greatest Hits/Foo Fighters - Breakout.mp3
+C:/Users/Rik/Music/Artists/Foo Fighters/Greatest Hits/Foo Fighters - Everlong.mp3
+C:/Users/Rik/Music/Artists/Foo Fighters/Greatest Hits/Foo Fighters - Learn to Fly.mp3
+C:/Users/Rik/Music/Artists/Foo Fighters/Greatest Hits/Foo Fighters - Long Road to Ruin.mp3
+C:/Users/Rik/Music/Artists/Foo Fighters/Greatest Hits/Foo Fighters - Monkey Wrench.mp3
+C:/Users/Rik/Music/Artists/Foo Fighters/Greatest Hits/Foo Fighters - My Hero.mp3
+C:/Users/Rik/Music/Artists/Foo Fighters/Greatest Hits/Foo Fighters - The Pretender.mp3
+C:/Users/Rik/Music/Artists/Foo Fighters/Greatest Hits/Foo Fighters - This Is a Call.mp3
+C:/Users/Rik/Music/Artists/Foo Fighters/Greatest Hits/Foo Fighters - Times Like These.mp3
+C:/Users/Rik/Music/Artists/Foo Fighters/Greatest Hits/Foo Fighters - Wheels.mp3
+C:/Users/Rik/Music/Artists/Foo Fighters/Greatest Hits/Foo Fighters - Word Forward.mp3
+C:/Users/Rik/Music/Artists/Foo Fighters/Wasting Light/Foo Fighters - A Matter of Time.mp3
+C:/Users/Rik/Music/Artists/Foo Fighters/Wasting Light/Foo Fighters - Arlandria.mp3
+C:/Users/Rik/Music/Artists/Foo Fighters/Wasting Light/Foo Fighters - Back & Forth.mp3
+C:/Users/Rik/Music/Artists/Foo Fighters/Wasting Light/Foo Fighters - Bridge Burning.mp3
+C:/Users/Rik/Music/Artists/Foo Fighters/Wasting Light/Foo Fighters - Dear Rosemary.mp3
+C:/Users/Rik/Music/Artists/Foo Fighters/Wasting Light/Foo Fighters - Miss the Misery.mp3
+C:/Users/Rik/Music/Artists/Foo Fighters/Wasting Light/Foo Fighters - Rope.mp3
+C:/Users/Rik/Music/Artists/Foo Fighters/Wasting Light/Foo Fighters - These Days.mp3
+C:/Users/Rik/Music/Artists/Foo Fighters/Wasting Light/Foo Fighters - Walk.mp3
+C:/Users/Rik/Music/Artists/Go Back To The Zoo/Benny Blisto/Go Back to the Zoo - Beam Me Up.mp3
+C:/Users/Rik/Music/Artists/Go Back To The Zoo/Benny Blisto/Go Back to the Zoo - Electric.mp3
+C:/Users/Rik/Music/Artists/Go Back To The Zoo/Benny Blisto/Go Back to the Zoo - Fuck You.mp3
+C:/Users/Rik/Music/Artists/Go Back To The Zoo/Benny Blisto/Go Back to the Zoo - Hey Dj.mp3
+C:/Users/Rik/Music/Artists/Go Back To The Zoo/Benny Blisto/Go Back to the Zoo - I Lov It.mp3
+C:/Users/Rik/Music/Artists/Go Back To The Zoo/Benny Blisto/Go Back to the Zoo - I'm the Night (See You Later).mp3
+C:/Users/Rik/Music/Artists/Go Back To The Zoo/Benny Blisto/Go Back to the Zoo - Nicer.mp3
+C:/Users/Rik/Music/Artists/Go Back To The Zoo/Benny Blisto/Go Back to the Zoo - Oh No (We Stayed).mp3
+C:/Users/Rik/Music/Artists/Go Back To The Zoo/Benny Blisto/Go Back to the Zoo - Sweet World.mp3
+C:/Users/Rik/Music/Artists/Good Charlotte/Cardiology/Good Charlotte - 1979.mp3
+C:/Users/Rik/Music/Artists/Good Charlotte/Cardiology/Good Charlotte - Alive.mp3
+C:/Users/Rik/Music/Artists/Good Charlotte/Cardiology/Good Charlotte - Cardiology.mp3
+C:/Users/Rik/Music/Artists/Good Charlotte/Cardiology/Good Charlotte - Counting the Days.mp3
+C:/Users/Rik/Music/Artists/Good Charlotte/Cardiology/Good Charlotte - Harlow's Song (Can't Dream Without You).mp3
+C:/Users/Rik/Music/Artists/Good Charlotte/Cardiology/Good Charlotte - Interlude (The Fifth Chamber).mp3
+C:/Users/Rik/Music/Artists/Good Charlotte/Cardiology/Good Charlotte - Introduction to Cardiology.mp3
+C:/Users/Rik/Music/Artists/Good Charlotte/Cardiology/Good Charlotte - Last Night.mp3
+C:/Users/Rik/Music/Artists/Good Charlotte/Cardiology/Good Charlotte - Let the Music Play.mp3
+C:/Users/Rik/Music/Artists/Good Charlotte/Cardiology/Good Charlotte - Like It's Her Birthday.mp3
+C:/Users/Rik/Music/Artists/Good Charlotte/Cardiology/Good Charlotte - Right Where I Belong.mp3
+C:/Users/Rik/Music/Artists/Good Charlotte/Cardiology/Good Charlotte - Sex On the Radio.mp3
+C:/Users/Rik/Music/Artists/Good Charlotte/Cardiology/Good Charlotte - Silver Screen Romance.mp3
+C:/Users/Rik/Music/Artists/Good Charlotte/Cardiology/Good Charlotte - Standing Ovation.mp3
+C:/Users/Rik/Music/Artists/Good Charlotte/Cardiology/Good Charlotte - There She Goes.mp3
+C:/Users/Rik/Music/Artists/Green Day/21st Century Breakdown/Green Day - 21 Guns.mp3
+C:/Users/Rik/Music/Artists/Green Day/21st Century Breakdown/Green Day - 21st Century Breakdown.mp3
+C:/Users/Rik/Music/Artists/Green Day/21st Century Breakdown/Green Day - American Eulogy.mp3
+C:/Users/Rik/Music/Artists/Green Day/21st Century Breakdown/Green Day - Before the Lobotomy.mp3
+C:/Users/Rik/Music/Artists/Green Day/21st Century Breakdown/Green Day - Christian's Inferno.mp3
+C:/Users/Rik/Music/Artists/Green Day/21st Century Breakdown/Green Day - East Jesus Nowhere.mp3
+C:/Users/Rik/Music/Artists/Green Day/21st Century Breakdown/Green Day - Horseshoes and Handgrenades.mp3
+C:/Users/Rik/Music/Artists/Green Day/21st Century Breakdown/Green Day - Know Your Enemy.mp3
+C:/Users/Rik/Music/Artists/Green Day/21st Century Breakdown/Green Day - Last Night On Earth.mp3
+C:/Users/Rik/Music/Artists/Green Day/21st Century Breakdown/Green Day - Last of the American Girls.mp3
+C:/Users/Rik/Music/Artists/Green Day/21st Century Breakdown/Green Day - Murder City.mp3
+C:/Users/Rik/Music/Artists/Green Day/21st Century Breakdown/Green Day - Peacemaker.mp3
+C:/Users/Rik/Music/Artists/Green Day/21st Century Breakdown/Green Day - Restless Heart Syndrome.mp3
+C:/Users/Rik/Music/Artists/Green Day/21st Century Breakdown/Green Day - See the Light.mp3
+C:/Users/Rik/Music/Artists/Green Day/21st Century Breakdown/Green Day - The Static Age.mp3
+C:/Users/Rik/Music/Artists/Green Day/21st Century Breakdown/Green Day - Viva La Gloria (Little Girl).mp3
+C:/Users/Rik/Music/Artists/Green Day/American Idiot/Green Day - American Idiot.mp3
+C:/Users/Rik/Music/Artists/Green Day/American Idiot/Green Day - Are We the Waiting.mp3
+C:/Users/Rik/Music/Artists/Green Day/American Idiot/Green Day - Boulevard of Broken Dreams.mp3
+C:/Users/Rik/Music/Artists/Green Day/American Idiot/Green Day - Extraordinary Girl.mp3
+C:/Users/Rik/Music/Artists/Green Day/American Idiot/Green Day - Give Me Novacaine.mp3
+C:/Users/Rik/Music/Artists/Green Day/American Idiot/Green Day - Holiday.mp3
+C:/Users/Rik/Music/Artists/Green Day/American Idiot/Green Day - Homecoming.mp3
+C:/Users/Rik/Music/Artists/Green Day/American Idiot/Green Day - Jesus of Suburbia.mp3
+C:/Users/Rik/Music/Artists/Green Day/American Idiot/Green Day - Letterbomb.mp3
+C:/Users/Rik/Music/Artists/Green Day/American Idiot/Green Day - She's a Rebel.mp3
+C:/Users/Rik/Music/Artists/Green Day/American Idiot/Green Day - St. Jimmy.mp3
+C:/Users/Rik/Music/Artists/Green Day/American Idiot/Green Day - Wake Me Up When September Ends.mp3
+C:/Users/Rik/Music/Artists/Green Day/American Idiot/Green Day - Whatsername.mp3
+C:/Users/Rik/Music/Artists/Green Day/Greatest Hits/Green Day - All the Time.mp3
+C:/Users/Rik/Music/Artists/Green Day/Greatest Hits/Green Day - Armatage Shanks.mp3
+C:/Users/Rik/Music/Artists/Green Day/Greatest Hits/Green Day - Bascet Case.mp3
+C:/Users/Rik/Music/Artists/Green Day/Greatest Hits/Green Day - Brat.mp3
+C:/Users/Rik/Music/Artists/Green Day/Greatest Hits/Green Day - Burnout.mp3
+C:/Users/Rik/Music/Artists/Green Day/Greatest Hits/Green Day - Chump.mp3
+C:/Users/Rik/Music/Artists/Green Day/Greatest Hits/Green Day - Church On Sunday.mp3
+C:/Users/Rik/Music/Artists/Green Day/Greatest Hits/Green Day - Coming Clean.mp3
+C:/Users/Rik/Music/Artists/Green Day/Greatest Hits/Green Day - Desensitized.mp3
+C:/Users/Rik/Music/Artists/Green Day/Greatest Hits/Green Day - Emenius Sleepus.mp3
+C:/Users/Rik/Music/Artists/Green Day/Greatest Hits/Green Day - Fashion Victim.mp3
+C:/Users/Rik/Music/Artists/Green Day/Greatest Hits/Green Day - Geek Stink Breath.mp3
+C:/Users/Rik/Music/Artists/Green Day/Greatest Hits/Green Day - Good Riddance (Time of Your Life).mp3
+C:/Users/Rik/Music/Artists/Green Day/Greatest Hits/Green Day - In the End.mp3
+C:/Users/Rik/Music/Artists/Green Day/Greatest Hits/Green Day - J.A.R. (Jason Andrew Relva).mp3
+C:/Users/Rik/Music/Artists/Green Day/Greatest Hits/Green Day - Jaded.mp3
+C:/Users/Rik/Music/Artists/Green Day/Greatest Hits/Green Day - Maria.mp3
+C:/Users/Rik/Music/Artists/Green Day/Greatest Hits/Green Day - Nice Guys Finish Last.mp3
+C:/Users/Rik/Music/Artists/Green Day/Greatest Hits/Green Day - Poprocks & Coke.mp3
+C:/Users/Rik/Music/Artists/Green Day/Greatest Hits/Green Day - Redundant.mp3
+C:/Users/Rik/Music/Artists/Green Day/Greatest Hits/Green Day - Scumbag.mp3
+C:/Users/Rik/Music/Artists/Green Day/Greatest Hits/Green Day - She.mp3
+C:/Users/Rik/Music/Artists/Green Day/Greatest Hits/Green Day - Stuck With Me.mp3
+C:/Users/Rik/Music/Artists/Green Day/Greatest Hits/Green Day - Suffocate.mp3
+C:/Users/Rik/Music/Artists/Green Day/Greatest Hits/Green Day - The Grouch.mp3
+C:/Users/Rik/Music/Artists/Green Day/Greatest Hits/Green Day - The Saints Are Coming.mp3
+C:/Users/Rik/Music/Artists/Green Day/Greatest Hits/Green Day - Waiting.mp3
+C:/Users/Rik/Music/Artists/Green Day/Greatest Hits/Green Day - Walking Alone.mp3
+C:/Users/Rik/Music/Artists/Green Day/Greatest Hits/Green Day - Walking Contradiction.mp3
+C:/Users/Rik/Music/Artists/Green Day/Greatest Hits/Green Day - Warning.mp3
+C:/Users/Rik/Music/Artists/Green Day/Greatest Hits/Green Day - Welcome to Paradise.mp3
+C:/Users/Rik/Music/Artists/Kaiser Chiefs/Off With Their Heads/Kaiser Chiefs - Addicted to Drugs.mp3
+C:/Users/Rik/Music/Artists/Kaiser Chiefs/Off With Their Heads/Kaiser Chiefs - Always Happens Like That.mp3
+C:/Users/Rik/Music/Artists/Kaiser Chiefs/Off With Their Heads/Kaiser Chiefs - Can't Say What I Mean.mp3
+C:/Users/Rik/Music/Artists/Kaiser Chiefs/Off With Their Heads/Kaiser Chiefs - Good Days Bad Days.mp3
+C:/Users/Rik/Music/Artists/Kaiser Chiefs/Off With Their Heads/Kaiser Chiefs - Half the Truth.mp3
+C:/Users/Rik/Music/Artists/Kaiser Chiefs/Off With Their Heads/Kaiser Chiefs - Like It Too Much.mp3
+C:/Users/Rik/Music/Artists/Kaiser Chiefs/Off With Their Heads/Kaiser Chiefs - Never Miss a Beat.mp3
+C:/Users/Rik/Music/Artists/Kaiser Chiefs/Off With Their Heads/Kaiser Chiefs - Spanish Metal.mp3
+C:/Users/Rik/Music/Artists/Kaiser Chiefs/Off With Their Heads/Kaiser Chiefs - Tomato In the Rain.mp3
+C:/Users/Rik/Music/Artists/Kaiser Chiefs/Off With Their Heads/Kaiser Chiefs - You Want History.mp3
+C:/Users/Rik/Music/Artists/Kaiser Chiefs/Yours Truly, Angry Mob/Kaiser Chiefs - Boxing Champ.mp3
+C:/Users/Rik/Music/Artists/Kaiser Chiefs/Yours Truly, Angry Mob/Kaiser Chiefs - Everything Is Average Nowadays.mp3
+C:/Users/Rik/Music/Artists/Kaiser Chiefs/Yours Truly, Angry Mob/Kaiser Chiefs - Heat Dies Down.mp3
+C:/Users/Rik/Music/Artists/Kaiser Chiefs/Yours Truly, Angry Mob/Kaiser Chiefs - Highroyds.mp3
+C:/Users/Rik/Music/Artists/Kaiser Chiefs/Yours Truly, Angry Mob/Kaiser Chiefs - I Can Do Without You.mp3
+C:/Users/Rik/Music/Artists/Kaiser Chiefs/Yours Truly, Angry Mob/Kaiser Chiefs - Learnt My Lesson Well.mp3
+C:/Users/Rik/Music/Artists/Kaiser Chiefs/Yours Truly, Angry Mob/Kaiser Chiefs - Love's Not a Competition (But I'm Winning).mp3
+C:/Users/Rik/Music/Artists/Kaiser Chiefs/Yours Truly, Angry Mob/Kaiser Chiefs - My Kind of Guy.mp3
+C:/Users/Rik/Music/Artists/Kaiser Chiefs/Yours Truly, Angry Mob/Kaiser Chiefs - Retirement.mp3
+C:/Users/Rik/Music/Artists/Kaiser Chiefs/Yours Truly, Angry Mob/Kaiser Chiefs - Ruby.mp3
+C:/Users/Rik/Music/Artists/Kaiser Chiefs/Yours Truly, Angry Mob/Kaiser Chiefs - Thank You Very Much.mp3
+C:/Users/Rik/Music/Artists/Kaiser Chiefs/Yours Truly, Angry Mob/Kaiser Chiefs - The Angry Mob.mp3
+C:/Users/Rik/Music/Artists/Kaiser Chiefs/Yours Truly, Angry Mob/Kaiser Chiefs - Try Your Best.mp3
+C:/Users/Rik/Music/Artists/Keane/Keane - Everybody's Changing.mp3
+C:/Users/Rik/Music/Artists/Keane/Keane - Is It Any Wonder.mp3
+C:/Users/Rik/Music/Artists/Keane/Keane - Somewhere Only We Know.mp3
+C:/Users/Rik/Music/Artists/Keane/Keane - This Is the Last Time.mp3
+C:/Users/Rik/Music/Artists/Keane/Perfect Symmetry/Keane - Again & Again.mp3
+C:/Users/Rik/Music/Artists/Keane/Perfect Symmetry/Keane - Better Than This.mp3
+C:/Users/Rik/Music/Artists/Keane/Perfect Symmetry/Keane - Black Burning Heart.mp3
+C:/Users/Rik/Music/Artists/Keane/Perfect Symmetry/Keane - Lovers Are Losing.mp3
+C:/Users/Rik/Music/Artists/Keane/Perfect Symmetry/Keane - Perfect Symmetry.mp3
+C:/Users/Rik/Music/Artists/Keane/Perfect Symmetry/Keane - Playing Along.mp3
+C:/Users/Rik/Music/Artists/Keane/Perfect Symmetry/Keane - Pretend That You're Alone.mp3
+C:/Users/Rik/Music/Artists/Keane/Perfect Symmetry/Keane - Spiralling.mp3
+C:/Users/Rik/Music/Artists/Keane/Perfect Symmetry/Keane - You Don't See Me.mp3
+C:/Users/Rik/Music/Artists/Kensington/Borders/Kensington - All That I Know.mp3
+C:/Users/Rik/Music/Artists/Kensington/Borders/Kensington - Franklin Exits.mp3
+C:/Users/Rik/Music/Artists/Kensington/Borders/Kensington - I Was Too Scared.mp3
+C:/Users/Rik/Music/Artists/Kensington/Borders/Kensington - Not As Bright.mp3
+C:/Users/Rik/Music/Artists/Kensington/Borders/Kensington - So Am I.mp3
+C:/Users/Rik/Music/Artists/Kensington/Borders/Kensington - The Heart of It.mp3
+C:/Users/Rik/Music/Artists/Kensington/Borders/Kensington - Thieves and Murderers.mp3
+C:/Users/Rik/Music/Artists/Kensington/Borders/Kensington - Waiting For a Sign.mp3
+C:/Users/Rik/Music/Artists/Kensington/Borders/Kensington - What's Gotten Into Us.mp3
+C:/Users/Rik/Music/Artists/Kensington/Borders/Kensington - When It All Falls Down.mp3
+C:/Users/Rik/Music/Artists/Kensington/Borders/Kensington - Youth.mp3
+C:/Users/Rik/Music/Artists/Kings of Leon/Come Around Sundown/Kings of Leon - Back Down South.mp3
+C:/Users/Rik/Music/Artists/Kings of Leon/Come Around Sundown/Kings of Leon - Beach Side.mp3
+C:/Users/Rik/Music/Artists/Kings of Leon/Come Around Sundown/Kings of Leon - Birthday.mp3
+C:/Users/Rik/Music/Artists/Kings of Leon/Come Around Sundown/Kings of Leon - Mary.mp3
+C:/Users/Rik/Music/Artists/Kings of Leon/Come Around Sundown/Kings of Leon - Mi Amigo.mp3
+C:/Users/Rik/Music/Artists/Kings of Leon/Come Around Sundown/Kings of Leon - No Money.mp3
+C:/Users/Rik/Music/Artists/Kings of Leon/Come Around Sundown/Kings of Leon - Pickup Truck.mp3
+C:/Users/Rik/Music/Artists/Kings of Leon/Come Around Sundown/Kings of Leon - Pony Up.mp3
+C:/Users/Rik/Music/Artists/Kings of Leon/Come Around Sundown/Kings of Leon - Pyro.mp3
+C:/Users/Rik/Music/Artists/Kings of Leon/Come Around Sundown/Kings of Leon - Radioactive.mp3
+C:/Users/Rik/Music/Artists/Kings of Leon/Come Around Sundown/Kings of Leon - The End.mp3
+C:/Users/Rik/Music/Artists/Kings of Leon/Come Around Sundown/Kings of Leon - The Face.mp3
+C:/Users/Rik/Music/Artists/Kings of Leon/Come Around Sundown/Kings of Leon - The Immortals.mp3
+C:/Users/Rik/Music/Artists/Kings of Leon/Only By The Night/Kings of Leon - Be Somebody.mp3
+C:/Users/Rik/Music/Artists/Kings of Leon/Only By The Night/Kings of Leon - Closer.mp3
+C:/Users/Rik/Music/Artists/Kings of Leon/Only By The Night/Kings of Leon - Crawl.mp3
+C:/Users/Rik/Music/Artists/Kings of Leon/Only By The Night/Kings of Leon - I Want You.mp3
+C:/Users/Rik/Music/Artists/Kings of Leon/Only By The Night/Kings of Leon - Manhattan.mp3
+C:/Users/Rik/Music/Artists/Kings of Leon/Only By The Night/Kings of Leon - Notion.mp3
+C:/Users/Rik/Music/Artists/Kings of Leon/Only By The Night/Kings of Leon - Sex On Fire.mp3
+C:/Users/Rik/Music/Artists/Kings of Leon/Only By The Night/Kings of Leon - Use Somebody.mp3
+C:/Users/Rik/Music/Artists/Lifehouse/Smoke & Mirrors/Lifehouse - All In.mp3
+C:/Users/Rik/Music/Artists/Lifehouse/Smoke & Mirrors/Lifehouse - All That I'm Asking For.mp3
+C:/Users/Rik/Music/Artists/Lifehouse/Smoke & Mirrors/Lifehouse - By Your Side.mp3
+C:/Users/Rik/Music/Artists/Lifehouse/Smoke & Mirrors/Lifehouse - Crash and Burn.mp3
+C:/Users/Rik/Music/Artists/Lifehouse/Smoke & Mirrors/Lifehouse - Falling In.mp3
+C:/Users/Rik/Music/Artists/Lifehouse/Smoke & Mirrors/Lifehouse - From Where You Are.mp3
+C:/Users/Rik/Music/Artists/Lifehouse/Smoke & Mirrors/Lifehouse - Had Enough.mp3
+C:/Users/Rik/Music/Artists/Lifehouse/Smoke & Mirrors/Lifehouse - Halfway Gone.mp3
+C:/Users/Rik/Music/Artists/Lifehouse/Smoke & Mirrors/Lifehouse - In Your Skin.mp3
+C:/Users/Rik/Music/Artists/Lifehouse/Smoke & Mirrors/Lifehouse - It Is What It Is.mp3
+C:/Users/Rik/Music/Artists/Lifehouse/Smoke & Mirrors/Lifehouse - Smoke & Mirrors.mp3
+C:/Users/Rik/Music/Artists/Lifehouse/Smoke & Mirrors/Lifehouse - Wrecking Ball.mp3
+C:/Users/Rik/Music/Artists/Lifehouse/Who We Are/Lifehouse - Bridges.mp3
+C:/Users/Rik/Music/Artists/Lifehouse/Who We Are/Lifehouse - Disarray.mp3
+C:/Users/Rik/Music/Artists/Lifehouse/Who We Are/Lifehouse - Easier to Be.mp3
+C:/Users/Rik/Music/Artists/Lifehouse/Who We Are/Lifehouse - First Time.mp3
+C:/Users/Rik/Music/Artists/Lifehouse/Who We Are/Lifehouse - Learn You Inside Out.mp3
+C:/Users/Rik/Music/Artists/Lifehouse/Who We Are/Lifehouse - Make Me Over.mp3
+C:/Users/Rik/Music/Artists/Lifehouse/Who We Are/Lifehouse - Mesmerized.mp3
+C:/Users/Rik/Music/Artists/Lifehouse/Who We Are/Lifehouse - Storm.mp3
+C:/Users/Rik/Music/Artists/Lifehouse/Who We Are/Lifehouse - Whatever It Takes.mp3
+C:/Users/Rik/Music/Artists/Lifehouse/Who We Are/Lifehouse - Who We Are.mp3
+C:/Users/Rik/Music/Artists/Linking Park/Hybrid Theory/Linkin Park - A Place For My Head.mp3
+C:/Users/Rik/Music/Artists/Linking Park/Hybrid Theory/Linkin Park - Crawling.mp3
+C:/Users/Rik/Music/Artists/Linking Park/Hybrid Theory/Linkin Park - Forgotten.mp3
+C:/Users/Rik/Music/Artists/Linking Park/Hybrid Theory/Linkin Park - In the End.mp3
+C:/Users/Rik/Music/Artists/Linking Park/Hybrid Theory/Linkin Park - One Step Closer.mp3
+C:/Users/Rik/Music/Artists/Linking Park/Hybrid Theory/Linkin Park - Papercut.mp3
+C:/Users/Rik/Music/Artists/Linking Park/Hybrid Theory/Linkin Park - Points of Authority.mp3
+C:/Users/Rik/Music/Artists/Linking Park/Hybrid Theory/Linkin Park - Pushing Me Away.mp3
+C:/Users/Rik/Music/Artists/Linking Park/Hybrid Theory/Linkin Park - Runaway.mp3
+C:/Users/Rik/Music/Artists/Linking Park/Hybrid Theory/Linkin Park - With You.mp3
+C:/Users/Rik/Music/Artists/Lostprophets/Liberation Transmission/Lostprophets - 4am Forever.mp3
+C:/Users/Rik/Music/Artists/Lostprophets/Liberation Transmission/Lostprophets - A Town Called Hypocrisy.mp3
+C:/Users/Rik/Music/Artists/Lostprophets/Liberation Transmission/Lostprophets - Always All Ways (Apologies, Glances and Messed Up Chances).mp3
+C:/Users/Rik/Music/Artists/Lostprophets/Liberation Transmission/Lostprophets - Broken Hearts, Torn Up Letters and the Story of a Lonely Girl.mp3
+C:/Users/Rik/Music/Artists/Lostprophets/Liberation Transmission/Lostprophets - Can't Catch Tomorrow (Good Shoes Won't Save You This Time).mp3
+C:/Users/Rik/Music/Artists/Lostprophets/Liberation Transmission/Lostprophets - Can't Stop, Gotta Date With Hate.mp3
+C:/Users/Rik/Music/Artists/Lostprophets/Liberation Transmission/Lostprophets - Everybody's Screaming !!!.mp3
+C:/Users/Rik/Music/Artists/Lostprophets/Liberation Transmission/Lostprophets - Everyday Combat.mp3
+C:/Users/Rik/Music/Artists/Lostprophets/Liberation Transmission/Lostprophets - For All These Times Son, For All These Times.mp3
+C:/Users/Rik/Music/Artists/Lostprophets/Liberation Transmission/Lostprophets - Heaven For the Weather, Hell For the Company.mp3
+C:/Users/Rik/Music/Artists/Lostprophets/Liberation Transmission/Lostprophets - Rooftops (A Liberation Broadcast).mp3
+C:/Users/Rik/Music/Artists/Lostprophets/Liberation Transmission/Lostprophets - The New Transmission.mp3
+C:/Users/Rik/Music/Artists/Matchbook Romance/Voices/Matchbook Romance - Goody, Like Two Shoes.mp3
+C:/Users/Rik/Music/Artists/Matchbook Romance/Voices/Matchbook Romance - Monsters.mp3
+C:/Users/Rik/Music/Artists/Matchbook Romance/Voices/Matchbook Romance - My Mannequin Can Dance.mp3
+C:/Users/Rik/Music/Artists/Matchbook Romance/Voices/Matchbook Romance - Portrait.mp3
+C:/Users/Rik/Music/Artists/Matchbook Romance/Voices/Matchbook Romance - Singing Bridges (We All Fall).mp3
+C:/Users/Rik/Music/Artists/Matchbook Romance/Voices/Matchbook Romance - Surrender.mp3
+C:/Users/Rik/Music/Artists/Matchbook Romance/Voices/Matchbook Romance - What a Sight.mp3
+C:/Users/Rik/Music/Artists/Neon Trees/Habits/Neon Trees - 1983.mp3
+C:/Users/Rik/Music/Artists/Neon Trees/Habits/Neon Trees - Animal.mp3
+C:/Users/Rik/Music/Artists/Neon Trees/Habits/Neon Trees - In the Next Room.mp3
+C:/Users/Rik/Music/Artists/Neon Trees/Habits/Neon Trees - Sins of My Youth.mp3
+C:/Users/Rik/Music/Artists/Neon Trees/Habits/Neon Trees - Your Surrender.mp3
+C:/Users/Rik/Music/Artists/Nickelback/Dark Horse/Nickelback - Gotta Be Somebody.mp3
+C:/Users/Rik/Music/Artists/Nickelback/Dark Horse/Nickelback - I'd Come For You.mp3
+C:/Users/Rik/Music/Artists/Nickelback/Dark Horse/Nickelback - If Today Was Your Last Day.mp3
+C:/Users/Rik/Music/Artists/Nickelback/Dark Horse/Nickelback - Just to Get High.mp3
+C:/Users/Rik/Music/Artists/Nickelback/Dark Horse/Nickelback - Never Gonna Be Alone.mp3
+C:/Users/Rik/Music/Artists/Nickelback/Dark Horse/Nickelback - This Afternoon.mp3
+C:/Users/Rik/Music/Artists/Nickelback/Nickelback - How You Remind Me.mp3
+C:/Users/Rik/Music/Artists/Nickelback/Nickelback - Photograph.mp3
+C:/Users/Rik/Music/Artists/OneRepublic/Waking Up/Onerepublic - All the Right Moves.mp3
+C:/Users/Rik/Music/Artists/OneRepublic/Waking Up/Onerepublic - Fear.mp3
+C:/Users/Rik/Music/Artists/OneRepublic/Waking Up/Onerepublic - Good Life.mp3
+C:/Users/Rik/Music/Artists/OneRepublic/Waking Up/Onerepublic - Secrets.mp3
+C:/Users/Rik/Music/Artists/Plain White T's/All That We Needed/Plain White T's - All That We Needed.mp3
+C:/Users/Rik/Music/Artists/Plain White T's/All That We Needed/Plain White T's - Anything.mp3
+C:/Users/Rik/Music/Artists/Plain White T's/All That We Needed/Plain White T's - Breakdown.mp3
+C:/Users/Rik/Music/Artists/Plain White T's/All That We Needed/Plain White T's - Faster.mp3
+C:/Users/Rik/Music/Artists/Plain White T's/All That We Needed/Plain White T's - Last Call.mp3
+C:/Users/Rik/Music/Artists/Plain White T's/All That We Needed/Plain White T's - Lazy Day Afternoon.mp3
+C:/Users/Rik/Music/Artists/Plain White T's/All That We Needed/Plain White T's - My Only One.mp3
+C:/Users/Rik/Music/Artists/Plain White T's/All That We Needed/Plain White T's - Revenge.mp3
+C:/Users/Rik/Music/Artists/Plain White T's/All That We Needed/Plain White T's - Sad Story.mp3
+C:/Users/Rik/Music/Artists/Plain White T's/All That We Needed/Plain White T's - Sing My Best.mp3
+C:/Users/Rik/Music/Artists/Plain White T's/All That We Needed/Plain White T's - Take Me Away.mp3
+C:/Users/Rik/Music/Artists/Plain White T's/All That We Needed/Plain White T's - What More Do You Want.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Greatest Hits/Red Hot Chili Peppers - Breaking the Girl.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Greatest Hits/Red Hot Chili Peppers - By the Way.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Greatest Hits/Red Hot Chili Peppers - Californication.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Greatest Hits/Red Hot Chili Peppers - Fortune Faded.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Greatest Hits/Red Hot Chili Peppers - Give It Away.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Greatest Hits/Red Hot Chili Peppers - Higher Ground.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Greatest Hits/Red Hot Chili Peppers - My Friends.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Greatest Hits/Red Hot Chili Peppers - Otherside.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Greatest Hits/Red Hot Chili Peppers - Parallel Universe.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Greatest Hits/Red Hot Chili Peppers - Save the Population.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Greatest Hits/Red Hot Chili Peppers - Scar Tissue.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Greatest Hits/Red Hot Chili Peppers - Soul to Squeeze.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Greatest Hits/Red Hot Chili Peppers - Under the Bridge.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Greatest Hits/Red Hot Chili Peppers - Universally Speaking.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Stadium Arcadium/Red Hot Chili Peppers - Animal Bar.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Stadium Arcadium/Red Hot Chili Peppers - Charlie.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Stadium Arcadium/Red Hot Chili Peppers - C'mon Girl.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Stadium Arcadium/Red Hot Chili Peppers - Dani California.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Stadium Arcadium/Red Hot Chili Peppers - Death of a Martian.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Stadium Arcadium/Red Hot Chili Peppers - Desecration Smile.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Stadium Arcadium/Red Hot Chili Peppers - Especially In Michigan.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Stadium Arcadium/Red Hot Chili Peppers - Hard to Concentrate.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Stadium Arcadium/Red Hot Chili Peppers - Hey.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Stadium Arcadium/Red Hot Chili Peppers - If.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Stadium Arcadium/Red Hot Chili Peppers - Make You Feel Better.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Stadium Arcadium/Red Hot Chili Peppers - She Looks to Me.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Stadium Arcadium/Red Hot Chili Peppers - She's Only 18.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Stadium Arcadium/Red Hot Chili Peppers - Slow Cheetah.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Stadium Arcadium/Red Hot Chili Peppers - Snow (Hey Oh).mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Stadium Arcadium/Red Hot Chili Peppers - So Much I.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Stadium Arcadium/Red Hot Chili Peppers - Stadium Arcadium.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Stadium Arcadium/Red Hot Chili Peppers - Storm In a Teacup.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Stadium Arcadium/Red Hot Chili Peppers - Strip My Mind.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Stadium Arcadium/Red Hot Chili Peppers - Tell Me Baby.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Stadium Arcadium/Red Hot Chili Peppers - Torture Me.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Stadium Arcadium/Red Hot Chili Peppers - Turn It Again.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Stadium Arcadium/Red Hot Chili Peppers - Warlocks.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Stadium Arcadium/Red Hot Chili Peppers - We Believe.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/Stadium Arcadium/Red Hot Chili Peppers - Wet Sand.mp3
+C:/Users/Rik/Music/Artists/Rooney/Calling The World/Rooney - All In Your Head.mp3
+C:/Users/Rik/Music/Artists/Rooney/Calling The World/Rooney - Are You Afraid.mp3
+C:/Users/Rik/Music/Artists/Rooney/Calling The World/Rooney - Believe In Me.mp3
+C:/Users/Rik/Music/Artists/Rooney/Calling The World/Rooney - Calling the World.mp3
+C:/Users/Rik/Music/Artists/Rooney/Calling The World/Rooney - Don't Come Around Again.mp3
+C:/Users/Rik/Music/Artists/Rooney/Calling The World/Rooney - I Should've Been After You.mp3
+C:/Users/Rik/Music/Artists/Rooney/Calling The World/Rooney - Love Me Or Leave Me.mp3
+C:/Users/Rik/Music/Artists/Rooney/Calling The World/Rooney - Paralyzed.mp3
+C:/Users/Rik/Music/Artists/Rooney/Calling The World/Rooney - What For.mp3
+C:/Users/Rik/Music/Artists/Savage Garden/Savage Garden/Savage Garden - A Thousand Words.mp3
+C:/Users/Rik/Music/Artists/Savage Garden/Savage Garden/Savage Garden - Break Me Shake Me.mp3
+C:/Users/Rik/Music/Artists/Savage Garden/Savage Garden/Savage Garden - Carry On Dancing.mp3
+C:/Users/Rik/Music/Artists/Savage Garden/Savage Garden/Savage Garden - I Want You.mp3
+C:/Users/Rik/Music/Artists/Savage Garden/Savage Garden/Savage Garden - To the Moon and Back.mp3
+C:/Users/Rik/Music/Artists/Savage Garden/Savage Garden/Savage Garden - Truly Madly Deeply.mp3
+C:/Users/Rik/Music/Artists/Savage Garden/Savage Garden/Savage Garden - Violet.mp3
+C:/Users/Rik/Music/Artists/Simple Plan/Simple Plan/Simple Plan - Generation.mp3
+C:/Users/Rik/Music/Artists/Simple Plan/Simple Plan/Simple Plan - I Can Wait Forever.mp3
+C:/Users/Rik/Music/Artists/Simple Plan/Simple Plan/Simple Plan - No Love.mp3
+C:/Users/Rik/Music/Artists/Simple Plan/Simple Plan/Simple Plan - Running Out of Time.mp3
+C:/Users/Rik/Music/Artists/Simple Plan/Simple Plan/Simple Plan - Save You.mp3
+C:/Users/Rik/Music/Artists/Simple Plan/Simple Plan/Simple Plan - Take My Hand.mp3
+C:/Users/Rik/Music/Artists/Simple Plan/Simple Plan/Simple Plan - The End.mp3
+C:/Users/Rik/Music/Artists/Simple Plan/Simple Plan/Simple Plan - Time to Say Goodbye.mp3
+C:/Users/Rik/Music/Artists/Simple Plan/Simple Plan/Simple Plan - What If.mp3
+C:/Users/Rik/Music/Artists/Simple Plan/Simple Plan/Simple Plan - When I'm Gone (Acoustic).mp3
+C:/Users/Rik/Music/Artists/Simple Plan/Simple Plan/Simple Plan - When I'm Gone.mp3
+C:/Users/Rik/Music/Artists/Simple Plan/Simple Plan/Simple Plan - Your Love Is a Lie.mp3
+C:/Users/Rik/Music/Artists/Snow Patrol/A Hundred Million Suns/Snow Patrol - Crack the Shutters.mp3
+C:/Users/Rik/Music/Artists/Snow Patrol/A Hundred Million Suns/Snow Patrol - Disaster Button.mp3
+C:/Users/Rik/Music/Artists/Snow Patrol/A Hundred Million Suns/Snow Patrol - Engines.mp3
+C:/Users/Rik/Music/Artists/Snow Patrol/A Hundred Million Suns/Snow Patrol - If There's a Rocket Tie Me to It.mp3
+C:/Users/Rik/Music/Artists/Snow Patrol/A Hundred Million Suns/Snow Patrol - Please Just Take These Photos From My Hands.mp3
+C:/Users/Rik/Music/Artists/Snow Patrol/A Hundred Million Suns/Snow Patrol - Take Back the City.mp3
+C:/Users/Rik/Music/Artists/Snow Patrol/Eyes Open/Snow Patrol - Chasing Cars.mp3
+C:/Users/Rik/Music/Artists/Snow Patrol/Eyes Open/Snow Patrol - Hands Open .mp3
+C:/Users/Rik/Music/Artists/Snow Patrol/Eyes Open/Snow Patrol - Headlights On Dark Roads.mp3
+C:/Users/Rik/Music/Artists/Snow Patrol/Eyes Open/Snow Patrol - In My Arms.mp3
+C:/Users/Rik/Music/Artists/Snow Patrol/Eyes Open/Snow Patrol - It's Beginning to Get to Me.mp3
+C:/Users/Rik/Music/Artists/Snow Patrol/Eyes Open/Snow Patrol - Open Your Eyes .mp3
+C:/Users/Rik/Music/Artists/Snow Patrol/Eyes Open/Snow Patrol - Shut Your Eyes .mp3
+C:/Users/Rik/Music/Artists/Snow Patrol/Eyes Open/Snow Patrol - Warmer Climate.mp3
+C:/Users/Rik/Music/Artists/Snow Patrol/Eyes Open/Snow Patrol - You're All I Have.mp3
+C:/Users/Rik/Music/Artists/Snow Patrol/Snow Patrol - Chocolate.mp3
+C:/Users/Rik/Music/Artists/Snow Patrol/Snow Patrol - Just Say Yes.mp3
+C:/Users/Rik/Music/Artists/Snow Patrol/Snow Patrol - Run.mp3
+C:/Users/Rik/Music/Artists/So They Say/Antidote for Irony/So They Say - Anxiety Is Setting In.mp3
+C:/Users/Rik/Music/Artists/So They Say/Antidote for Irony/So They Say - Good-Bye.mp3
+C:/Users/Rik/Music/Artists/So They Say/Antidote for Irony/So They Say - In Essence We Are Falling.mp3
+C:/Users/Rik/Music/Artists/So They Say/Antidote for Irony/So They Say - In Loving Memory Of....mp3
+C:/Users/Rik/Music/Artists/So They Say/Antidote for Irony/So They Say - Over Exposed Photo.mp3
+C:/Users/Rik/Music/Artists/So They Say/Antidote for Irony/So They Say - Talking In Circles.mp3
+C:/Users/Rik/Music/Artists/So They Say/Antidote for Irony/So They Say - The Burden.mp3
+C:/Users/Rik/Music/Artists/So They Say/Antidote for Irony/So They Say - You Asked, Where Are You Now.mp3
+C:/Users/Rik/Music/Artists/Stone Sour/Audio Secrecy/Stone Sour - Anna.mp3
+C:/Users/Rik/Music/Artists/Stone Sour/Audio Secrecy/Stone Sour - Dying.mp3
+C:/Users/Rik/Music/Artists/Stone Sour/Audio Secrecy/Stone Sour - Hate Not Gone.mp3
+C:/Users/Rik/Music/Artists/Stone Sour/Audio Secrecy/Stone Sour - Hesitate.mp3
+C:/Users/Rik/Music/Artists/Stone Sour/Audio Secrecy/Stone Sour - Home Again.mp3
+C:/Users/Rik/Music/Artists/Stone Sour/Audio Secrecy/Stone Sour - Imperfect.mp3
+C:/Users/Rik/Music/Artists/Stone Sour/Audio Secrecy/Stone Sour - Let's Be Honest.mp3
+C:/Users/Rik/Music/Artists/Stone Sour/Audio Secrecy/Stone Sour - Miracles.mp3
+C:/Users/Rik/Music/Artists/Stone Sour/Audio Secrecy/Stone Sour - Mission Statement.mp3
+C:/Users/Rik/Music/Artists/Stone Sour/Audio Secrecy/Stone Sour - Nylon 66.mp3
+C:/Users/Rik/Music/Artists/Stone Sour/Audio Secrecy/Stone Sour - Pieces.mp3
+C:/Users/Rik/Music/Artists/Stone Sour/Audio Secrecy/Stone Sour - Say You'll Haunt Me.mp3
+C:/Users/Rik/Music/Artists/Stone Sour/Audio Secrecy/Stone Sour - The Bitter End.mp3
+C:/Users/Rik/Music/Artists/Stone Sour/Audio Secrecy/Stone Sour - Threadbare.mp3
+C:/Users/Rik/Music/Artists/Stone Sour/Audio Secrecy/Stone Sour - Unfinished.mp3
+C:/Users/Rik/Music/Artists/Sum 41/Screaming Bloody Murder/Sum 41 - Baby You Don't Wanna Know.mp3
+C:/Users/Rik/Music/Artists/Sum 41/Screaming Bloody Murder/Sum 41 - Back Where I Belong.mp3
+C:/Users/Rik/Music/Artists/Sum 41/Screaming Bloody Murder/Sum 41 - Blood In My Eyes.mp3
+C:/Users/Rik/Music/Artists/Sum 41/Screaming Bloody Murder/Sum 41 - Crash.mp3
+C:/Users/Rik/Music/Artists/Sum 41/Screaming Bloody Murder/Sum 41 - Exit Song.mp3
+C:/Users/Rik/Music/Artists/Sum 41/Screaming Bloody Murder/Sum 41 - Happiness Machine.mp3
+C:/Users/Rik/Music/Artists/Sum 41/Screaming Bloody Murder/Sum 41 - Holy Image of Lies.mp3
+C:/Users/Rik/Music/Artists/Sum 41/Screaming Bloody Murder/Sum 41 - Jessica Kill.mp3
+C:/Users/Rik/Music/Artists/Sum 41/Screaming Bloody Murder/Sum 41 - Reason to Believe (Acoustic).mp3
+C:/Users/Rik/Music/Artists/Sum 41/Screaming Bloody Murder/Sum 41 - Reason to Believe.mp3
+C:/Users/Rik/Music/Artists/Sum 41/Screaming Bloody Murder/Sum 41 - Screaming Bloody Murder.mp3
+C:/Users/Rik/Music/Artists/Sum 41/Screaming Bloody Murder/Sum 41 - Sick of Everyone.mp3
+C:/Users/Rik/Music/Artists/Sum 41/Screaming Bloody Murder/Sum 41 - Skumfuk.mp3
+C:/Users/Rik/Music/Artists/Sum 41/Screaming Bloody Murder/Sum 41 - Time For You to Go.mp3
+C:/Users/Rik/Music/Artists/Sum 41/Screaming Bloody Murder/Sum 41 - What Am I to Say.mp3
+C:/Users/Rik/Music/Artists/Sum 41/Underclass Hero/Sum 41 - Best of Me.mp3
+C:/Users/Rik/Music/Artists/Sum 41/Underclass Hero/Sum 41 - Confusion and Frustration In Modern Times.mp3
+C:/Users/Rik/Music/Artists/Sum 41/Underclass Hero/Sum 41 - Count Your Last Blessings.mp3
+C:/Users/Rik/Music/Artists/Sum 41/Underclass Hero/Sum 41 - Dear Father.mp3
+C:/Users/Rik/Music/Artists/Sum 41/Underclass Hero/Sum 41 - King of Contradiction.mp3
+C:/Users/Rik/Music/Artists/Sum 41/Underclass Hero/Sum 41 - March of the Dogs.mp3
+C:/Users/Rik/Music/Artists/Sum 41/Underclass Hero/Sum 41 - Pull the Curtain.mp3
+C:/Users/Rik/Music/Artists/Sum 41/Underclass Hero/Sum 41 - So Long Goodbye.mp3
+C:/Users/Rik/Music/Artists/Sum 41/Underclass Hero/Sum 41 - Speak of the Devil.mp3
+C:/Users/Rik/Music/Artists/Sum 41/Underclass Hero/Sum 41 - The Jester.mp3
+C:/Users/Rik/Music/Artists/Sum 41/Underclass Hero/Sum 41 - Underclass Hero.mp3
+C:/Users/Rik/Music/Artists/Sum 41/Underclass Hero/Sum 41 - Walking Disaster.mp3
+C:/Users/Rik/Music/Artists/Sum 41/Underclass Hero/Sum 41 - With Me.mp3
+C:/Users/Rik/Music/Artists/The Academy Is/Almost Here/The Academy Is... - Almost Here.mp3
+C:/Users/Rik/Music/Artists/The Academy Is/Almost Here/The Academy Is... - Attention.mp3
+C:/Users/Rik/Music/Artists/The Academy Is/Almost Here/The Academy Is... - Black Mamba.mp3
+C:/Users/Rik/Music/Artists/The Academy Is/Almost Here/The Academy Is... - Checkmarks.mp3
+C:/Users/Rik/Music/Artists/The Academy Is/Almost Here/The Academy Is... - Classifieds.mp3
+C:/Users/Rik/Music/Artists/The Academy Is/Almost Here/The Academy Is... - Down and Out.mp3
+C:/Users/Rik/Music/Artists/The Academy Is/Almost Here/The Academy Is... - Season.mp3
+C:/Users/Rik/Music/Artists/The Academy Is/Almost Here/The Academy Is... - Skeptics and True Believers.mp3
+C:/Users/Rik/Music/Artists/The Academy Is/Almost Here/The Academy Is... - The Phrase That Pays.mp3
+C:/Users/Rik/Music/Artists/The All-American Rejects/Move Along/The All-American Rejects - 11.11 P.M.mp3
+C:/Users/Rik/Music/Artists/The All-American Rejects/Move Along/The All-American Rejects - Change Your Mind.mp3
+C:/Users/Rik/Music/Artists/The All-American Rejects/Move Along/The All-American Rejects - Dance Inside.mp3
+C:/Users/Rik/Music/Artists/The All-American Rejects/Move Along/The All-American Rejects - Dirty Little Secret.mp3
+C:/Users/Rik/Music/Artists/The All-American Rejects/Move Along/The All-American Rejects - I'm Waiting.mp3
+C:/Users/Rik/Music/Artists/The All-American Rejects/Move Along/The All-American Rejects - Move Along.mp3
+C:/Users/Rik/Music/Artists/The All-American Rejects/Move Along/The All-American Rejects - Stab My Back.mp3
+C:/Users/Rik/Music/Artists/The All-American Rejects/Move Along/The All-American Rejects - Top of the World.mp3
+C:/Users/Rik/Music/Artists/The All-American Rejects/When The World Comes Down/The All-American Rejects - Another Heart Calls.mp3
+C:/Users/Rik/Music/Artists/The All-American Rejects/When The World Comes Down/The All-American Rejects - Back to Me.mp3
+C:/Users/Rik/Music/Artists/The All-American Rejects/When The World Comes Down/The All-American Rejects - Believe.mp3
+C:/Users/Rik/Music/Artists/The All-American Rejects/When The World Comes Down/The All-American Rejects - Breakin'.mp3
+C:/Users/Rik/Music/Artists/The All-American Rejects/When The World Comes Down/The All-American Rejects - Damn Girl.mp3
+C:/Users/Rik/Music/Artists/The All-American Rejects/When The World Comes Down/The All-American Rejects - Fallin' Apart.mp3
+C:/Users/Rik/Music/Artists/The All-American Rejects/When The World Comes Down/The All-American Rejects - Gives You Hell.mp3
+C:/Users/Rik/Music/Artists/The All-American Rejects/When The World Comes Down/The All-American Rejects - I Wanna.mp3
+C:/Users/Rik/Music/Artists/The All-American Rejects/When The World Comes Down/The All-American Rejects - Mona Lisa.mp3
+C:/Users/Rik/Music/Artists/The All-American Rejects/When The World Comes Down/The All-American Rejects - Real World.mp3
+C:/Users/Rik/Music/Artists/The All-American Rejects/When The World Comes Down/The All-American Rejects - Sunshine.mp3
+C:/Users/Rik/Music/Artists/The All-American Rejects/When The World Comes Down/The All-American Rejects - The Wind Blows.mp3
+C:/Users/Rik/Music/Artists/The Fray/How To Save A Life/The Fray - All At Once.mp3
+C:/Users/Rik/Music/Artists/The Fray/How To Save A Life/The Fray - Dead Wrong.mp3
+C:/Users/Rik/Music/Artists/The Fray/How To Save A Life/The Fray - Fall Away.mp3
+C:/Users/Rik/Music/Artists/The Fray/How To Save A Life/The Fray - Heaven Forbid.mp3
+C:/Users/Rik/Music/Artists/The Fray/How To Save A Life/The Fray - How to Save a Life.mp3
+C:/Users/Rik/Music/Artists/The Fray/How To Save A Life/The Fray - Hundred.mp3
+C:/Users/Rik/Music/Artists/The Fray/How To Save A Life/The Fray - Little House.mp3
+C:/Users/Rik/Music/Artists/The Fray/How To Save A Life/The Fray - Look After You.mp3
+C:/Users/Rik/Music/Artists/The Fray/How To Save A Life/The Fray - Over My Head (Cable Car).mp3
+C:/Users/Rik/Music/Artists/The Fray/How To Save A Life/The Fray - She Is.mp3
+C:/Users/Rik/Music/Artists/The Fray/How To Save A Life/The Fray - Trust Me.mp3
+C:/Users/Rik/Music/Artists/The Hoosiers/The Illusion Of Safety/The Hoosiers - Bumpy Ride.mp3
+C:/Users/Rik/Music/Artists/The Hoosiers/The Illusion Of Safety/The Hoosiers - Choices.mp3
+C:/Users/Rik/Music/Artists/The Hoosiers/The Illusion Of Safety/The Hoosiers - Giddy Up.mp3
+C:/Users/Rik/Music/Artists/The Hoosiers/The Illusion Of Safety/The Hoosiers - Glorious.mp3
+C:/Users/Rik/Music/Artists/The Hoosiers/The Illusion Of Safety/The Hoosiers - Live By the Ocean.mp3
+C:/Users/Rik/Music/Artists/The Hoosiers/The Illusion Of Safety/The Hoosiers - Made to Measure.mp3
+C:/Users/Rik/Music/Artists/The Hoosiers/The Illusion Of Safety/The Hoosiers - Sarajevo.mp3
+C:/Users/Rik/Music/Artists/The Hoosiers/The Illusion Of Safety/The Hoosiers - Unlikely Hero.mp3
+C:/Users/Rik/Music/Artists/The Hoosiers/The Illusion Of Safety/The Hoosiers - Who Said Anything (About Falling In Love).mp3
+C:/Users/Rik/Music/Artists/The Killers/Day & Age/The Killers - A Crippling Blow.mp3
+C:/Users/Rik/Music/Artists/The Killers/Day & Age/The Killers - A Dustland Fairytale.mp3
+C:/Users/Rik/Music/Artists/The Killers/Day & Age/The Killers - Human.mp3
+C:/Users/Rik/Music/Artists/The Killers/Day & Age/The Killers - I Can't Stay.mp3
+C:/Users/Rik/Music/Artists/The Killers/Day & Age/The Killers - Joy Ride.mp3
+C:/Users/Rik/Music/Artists/The Killers/Day & Age/The Killers - Losing Touch.mp3
+C:/Users/Rik/Music/Artists/The Killers/Day & Age/The Killers - Neon Tiger.mp3
+C:/Users/Rik/Music/Artists/The Killers/Day & Age/The Killers - Spaceman.mp3
+C:/Users/Rik/Music/Artists/The Killers/Day & Age/The Killers - The World We Live In.mp3
+C:/Users/Rik/Music/Artists/The Killers/Day & Age/The Killers - This Is Your Life.mp3
+C:/Users/Rik/Music/Artists/The Killers/Hot Fuss/The Killers - All These Things That I've Done.mp3
+C:/Users/Rik/Music/Artists/The Killers/Hot Fuss/The Killers - Andy, You're a Star.mp3
+C:/Users/Rik/Music/Artists/The Killers/Hot Fuss/The Killers - Believe Me Natalie.mp3
+C:/Users/Rik/Music/Artists/The Killers/Hot Fuss/The Killers - Everything Will Be Alright.mp3
+C:/Users/Rik/Music/Artists/The Killers/Hot Fuss/The Killers - Glamorous Indie Rock & Roll.mp3
+C:/Users/Rik/Music/Artists/The Killers/Hot Fuss/The Killers - Indie Rock & Roll.mp3
+C:/Users/Rik/Music/Artists/The Killers/Hot Fuss/The Killers - Jenny Was a Friend of Mine.mp3
+C:/Users/Rik/Music/Artists/The Killers/Hot Fuss/The Killers - Midnight Show.mp3
+C:/Users/Rik/Music/Artists/The Killers/Hot Fuss/The Killers - Mr Brightside.mp3
+C:/Users/Rik/Music/Artists/The Killers/Hot Fuss/The Killers - Mr. Brightside.mp3
+C:/Users/Rik/Music/Artists/The Killers/Hot Fuss/The Killers - On Top.mp3
+C:/Users/Rik/Music/Artists/The Killers/Hot Fuss/The Killers - Smile Like You Mean It.mp3
+C:/Users/Rik/Music/Artists/The Killers/Hot Fuss/The Killers - The Ballad of Michael Valentine (Bonus).mp3
+C:/Users/Rik/Music/Artists/The Killers/Hot Fuss/The Killers - Under the Gun (Bonus).mp3
+C:/Users/Rik/Music/Artists/The Killers/Hot Fuss/The Killers - Who Let You Go (Bonus).mp3
+C:/Users/Rik/Music/Artists/The Offspring/Greatest Hits/The Offspring - (Can't Get My) Head Around You.mp3
+C:/Users/Rik/Music/Artists/The Offspring/Greatest Hits/The Offspring - All I Want.mp3
+C:/Users/Rik/Music/Artists/The Offspring/Greatest Hits/The Offspring - Can't Repeat.mp3
+C:/Users/Rik/Music/Artists/The Offspring/Greatest Hits/The Offspring - Come Out and Play (Keep 'em Separated).mp3
+C:/Users/Rik/Music/Artists/The Offspring/Greatest Hits/The Offspring - Defy You.mp3
+C:/Users/Rik/Music/Artists/The Offspring/Greatest Hits/The Offspring - Gone Away.mp3
+C:/Users/Rik/Music/Artists/The Offspring/Greatest Hits/The Offspring - Gotta Get Away.mp3
+C:/Users/Rik/Music/Artists/The Offspring/Greatest Hits/The Offspring - Hit That.mp3
+C:/Users/Rik/Music/Artists/The Offspring/Greatest Hits/The Offspring - Original Prankster.mp3
+C:/Users/Rik/Music/Artists/The Offspring/Greatest Hits/The Offspring - Pretty Fly (For a White Guy).mp3
+C:/Users/Rik/Music/Artists/The Offspring/Greatest Hits/The Offspring - Self Esteem.mp3
+C:/Users/Rik/Music/Artists/The Offspring/Greatest Hits/The Offspring - The Kids Aren't Alright.mp3
+C:/Users/Rik/Music/Artists/The Offspring/Greatest Hits/The Offspring - Want You Bad.mp3
+C:/Users/Rik/Music/Artists/The Offspring/Greatest Hits/The Offspring - Why Don't You Get a Job.mp3
+C:/Users/Rik/Music/Artists/The Script/Science & Faith/The Script - Dead Man Walking.mp3
+C:/Users/Rik/Music/Artists/The Script/Science & Faith/The Script - Exit Wounds.mp3
+C:/Users/Rik/Music/Artists/The Script/Science & Faith/The Script - For the First Time.mp3
+C:/Users/Rik/Music/Artists/The Script/Science & Faith/The Script - If You Ever Come Back.mp3
+C:/Users/Rik/Music/Artists/The Script/Science & Faith/The Script - Long Gone and Moved On.mp3
+C:/Users/Rik/Music/Artists/The Script/Science & Faith/The Script - Nothing.mp3
+C:/Users/Rik/Music/Artists/The Script/Science & Faith/The Script - Science & Faith.mp3
+C:/Users/Rik/Music/Artists/The Script/Science & Faith/The Script - This = Love.mp3
+C:/Users/Rik/Music/Artists/The Script/Science & Faith/The Script - You Won't Feel a Thing.mp3
+C:/Users/Rik/Music/Artists/The Script/The Script/The Script - Before the Worst.mp3
+C:/Users/Rik/Music/Artists/The Script/The Script/The Script - Breakeven.mp3
+C:/Users/Rik/Music/Artists/The Script/The Script/The Script - Fall For Anything.mp3
+C:/Users/Rik/Music/Artists/The Script/The Script/The Script - Rusty Halo.mp3
+C:/Users/Rik/Music/Artists/The Script/The Script/The Script - Talk You Down.mp3
+C:/Users/Rik/Music/Artists/The Script/The Script/The Script - The End Is Where I Begin.mp3
+C:/Users/Rik/Music/Artists/The Script/The Script/The Script - The Man Who Can't Be Moved.mp3
+C:/Users/Rik/Music/Artists/Three Days Grace/Life Starts Now/Three Days Grace - Bitter Taste.mp3
+C:/Users/Rik/Music/Artists/Three Days Grace/Life Starts Now/Three Days Grace - Break.mp3
+C:/Users/Rik/Music/Artists/Three Days Grace/Life Starts Now/Three Days Grace - Goin' Down.mp3
+C:/Users/Rik/Music/Artists/Three Days Grace/Life Starts Now/Three Days Grace - Last to Know.mp3
+C:/Users/Rik/Music/Artists/Three Days Grace/Life Starts Now/Three Days Grace - Life Starts Now.mp3
+C:/Users/Rik/Music/Artists/Three Days Grace/Life Starts Now/Three Days Grace - Lost In You.mp3
+C:/Users/Rik/Music/Artists/Three Days Grace/Life Starts Now/Three Days Grace - No More.mp3
+C:/Users/Rik/Music/Artists/Three Days Grace/Life Starts Now/Three Days Grace - Someone Who Cares.mp3
+C:/Users/Rik/Music/Artists/Three Days Grace/Life Starts Now/Three Days Grace - The Good Life.mp3
+C:/Users/Rik/Music/Artists/Three Days Grace/Life Starts Now/Three Days Grace - Without You.mp3
+C:/Users/Rik/Music/Artists/U2/No Line On The Horizon/U2 - Breathe.mp3
+C:/Users/Rik/Music/Artists/U2/No Line On The Horizon/U2 - Get On Your Boots.mp3
+C:/Users/Rik/Music/Artists/U2/No Line On The Horizon/U2 - I'll Go Crazy If I Don't Go Crazy Tonight.mp3
+C:/Users/Rik/Music/Artists/U2/No Line On The Horizon/U2 - Magnificent.mp3
+C:/Users/Rik/Music/Artists/U2/No Line On The Horizon/U2 - No Line On the Horizon.mp3
+C:/Users/Rik/Music/Artists/U2/No Line On The Horizon/U2 - Stand Up Comedy.mp3
+C:/Users/Rik/Music/Artists/U2/No Line On The Horizon/U2 - Unknown Caller.mp3
+C:/Users/Rik/Music/Artists/U2/No Line On The Horizon/U2 - White As Snow.mp3
+C:/Users/Rik/Music/Artists/U2/U2 - Beautiful Day.mp3
+C:/Users/Rik/Music/Artists/U2/U2 - Elevation.mp3
+C:/Users/Rik/Music/Artists/U2/U2 - I Still Haven't Found What I'm Looking For.mp3
+C:/Users/Rik/Music/Artists/U2/U2 - New Year's Day.mp3
+C:/Users/Rik/Music/Artists/U2/U2 - One.mp3
+C:/Users/Rik/Music/Artists/U2/U2 - Stuck In a Moment You Can't Get Out of.mp3
+C:/Users/Rik/Music/Artists/U2/U2 - Sunday Bloody Sunday .mp3
+C:/Users/Rik/Music/Artists/U2/U2 - Sweetest Thing.mp3
+C:/Users/Rik/Music/Artists/U2/U2 - The City of Blinding Lights.mp3
+C:/Users/Rik/Music/Artists/U2/U2 - Vertigo.mp3
+C:/Users/Rik/Music/Artists/U2/U2 - Where the Streets Have No Name.mp3
+C:/Users/Rik/Music/Artists/U2/U2 - With Or Without You.mp3
+C:/Users/Rik/Music/Artists/Weezer/Hurley/Weezer - All My Friends Are Insects (Bonus Track).mp3
+C:/Users/Rik/Music/Artists/Weezer/Hurley/Weezer - Brave New World.mp3
+C:/Users/Rik/Music/Artists/Weezer/Hurley/Weezer - Hang On.mp3
+C:/Users/Rik/Music/Artists/Weezer/Hurley/Weezer - I Want to Be Something (Bonus Track).mp3
+C:/Users/Rik/Music/Artists/Weezer/Hurley/Weezer - Memories.mp3
+C:/Users/Rik/Music/Artists/Weezer/Hurley/Weezer - Represent (Rocked Out Mix) %5Bbonus Track%5D.mp3
+C:/Users/Rik/Music/Artists/Weezer/Hurley/Weezer - Ruling Me.mp3
+C:/Users/Rik/Music/Artists/Weezer/Hurley/Weezer - Run Away.mp3
+C:/Users/Rik/Music/Artists/Weezer/Hurley/Weezer - Smart Girls.mp3
+C:/Users/Rik/Music/Artists/Weezer/Hurley/Weezer - Time Flies.mp3
+C:/Users/Rik/Music/Artists/Weezer/Hurley/Weezer - Trainwrecks.mp3
+C:/Users/Rik/Music/Artists/Weezer/Hurley/Weezer - Unspoken.mp3
+C:/Users/Rik/Music/Artists/Weezer/Hurley/Weezer - Viva La Vida (Bonus Track).mp3
+C:/Users/Rik/Music/Artists/Weezer/Hurley/Weezer - Where's My Sex.mp3
+C:/Users/Rik/Music/Artists/Yellowcard/Paper Walls/Yellowcard - Afraid.mp3
+C:/Users/Rik/Music/Artists/Yellowcard/Paper Walls/Yellowcard - Cut Me, Mick.mp3
+C:/Users/Rik/Music/Artists/Yellowcard/Paper Walls/Yellowcard - Date Line (I Am Gone).mp3
+C:/Users/Rik/Music/Artists/Yellowcard/Paper Walls/Yellowcard - Dear Bobbie.mp3
+C:/Users/Rik/Music/Artists/Yellowcard/Paper Walls/Yellowcard - Fighting.mp3
+C:/Users/Rik/Music/Artists/Yellowcard/Paper Walls/Yellowcard - Five Become Four.mp3
+C:/Users/Rik/Music/Artists/Yellowcard/Paper Walls/Yellowcard - Keeper.mp3
+C:/Users/Rik/Music/Artists/Yellowcard/Paper Walls/Yellowcard - Light Up the Sky.mp3
+C:/Users/Rik/Music/Artists/Yellowcard/Paper Walls/Yellowcard - Paper Walls.mp3
+C:/Users/Rik/Music/Artists/Yellowcard/Paper Walls/Yellowcard - Shadows and Regrets.mp3
+C:/Users/Rik/Music/Artists/Yellowcard/Paper Walls/Yellowcard - Shrink the World.mp3
+C:/Users/Rik/Music/Artists/Yellowcard/Paper Walls/Yellowcard - The Takedown.mp3
+C:/Users/Rik/Music/Artists/Yellowcard/Paper Walls/Yellowcard - You and Me and One Spotlight.mp3
+C:/Users/Rik/Music/Artists/Yellowcard/Yellowcard - October Nights.mp3
+C:/Users/Rik/Music/Artists/You Me At Six/Hold Me Down/You Me At Six - Contagious Chemistry.mp3
+C:/Users/Rik/Music/Artists/You Me At Six/Hold Me Down/You Me At Six - Fireworks.mp3
+C:/Users/Rik/Music/Artists/You Me At Six/Hold Me Down/You Me At Six - Hard to Swallow.mp3
+C:/Users/Rik/Music/Artists/You Me At Six/Hold Me Down/You Me At Six - Liquid Confidence.mp3
+C:/Users/Rik/Music/Artists/You Me At Six/Hold Me Down/You Me At Six - Playing the Blame Game.mp3
+C:/Users/Rik/Music/Artists/You Me At Six/Hold Me Down/You Me At Six - Safer to Hate Her.mp3
+C:/Users/Rik/Music/Artists/You Me At Six/Hold Me Down/You Me At Six - Stay With Me.mp3
+C:/Users/Rik/Music/Artists/You Me At Six/Hold Me Down/You Me At Six - Take Your Breath Away.mp3
+C:/Users/Rik/Music/Artists/You Me At Six/Hold Me Down/You Me At Six - There's No Such Thing As Accident.mp3
+C:/Users/Rik/Music/Artists/You Me At Six/Hold Me Down/You Me At Six - Trophy Eyes.mp3
+C:/Users/Rik/Music/Artists/You Me At Six/Hold Me Down/You Me At Six - Underdog.mp3
+C:/Users/Rik/Music/Old/Bad English - Time Stood Still.mp3
+C:/Users/Rik/Music/Old/Bon Jovi/Bon Jovi - In These Arms.mp3
+C:/Users/Rik/Music/Old/Bon Jovi/Bon Jovi - Livin' On a Prayer.mp3
+C:/Users/Rik/Music/Old/Don Henley - The Boys of Summer.mp3
+C:/Users/Rik/Music/Old/Duran Duran/Duran Duran - Ordinary World.mp3
+C:/Users/Rik/Music/Old/Duran Duran/Duran Duran - The Reflex.mp3
+C:/Users/Rik/Music/Old/Europe - The Final Countdown.mp3
+C:/Users/Rik/Music/Old/Genesis/Genesis - Land of Confusion.mp3
+C:/Users/Rik/Music/Old/Midnight Oil - Beds Are Burning.mp3
+C:/Users/Rik/Music/Old/No Doubt/No Doubt - It's My Life.mp3
+C:/Users/Rik/Music/Old/Survivor - Eye of the Tiger.mp3
+C:/Users/Rik/Music/Various/3 Doors Down/3 Doors Down - Here Without You.mp3
+C:/Users/Rik/Music/Various/3 Doors Down/3 Doors Down - Kryptonite.mp3
+C:/Users/Rik/Music/Various/A Silent Express - Will I Be Around.mp3
+C:/Users/Rik/Music/Various/Adam Lambert - Whataya Want From Me.mp3
+C:/Users/Rik/Music/Various/Alphabeat - The Spell.mp3
+C:/Users/Rik/Music/Various/Anouk/Anouk - Girl.mp3
+C:/Users/Rik/Music/Various/Anouk/Anouk - Nobody's Wife.mp3
+C:/Users/Rik/Music/Various/Anouk/Anouk - R U Kiddin' Me.mp3
+C:/Users/Rik/Music/Various/Avril Lavigne/Avril Lavigne - What the Hell.mp3
+C:/Users/Rik/Music/Various/Biffy Clyro - Many of Horror.mp3
+C:/Users/Rik/Music/Various/Brandon Flowers - Crossfire.mp3
+C:/Users/Rik/Music/Various/Carolina Liar - Show Me What Im Looking For.mp3
+C:/Users/Rik/Music/Various/Chumbawamba - Tubthumping.mp3
+C:/Users/Rik/Music/Various/Eagle Eye Cherry - Save Tonight.mp3
+C:/Users/Rik/Music/Various/Esm%C3%A9e Denters - Outta Here.mp3
+C:/Users/Rik/Music/Various/Falco Luneau - Nobody.mp3
+C:/Users/Rik/Music/Various/Freemasons - Uninvited.mp3
+C:/Users/Rik/Music/Various/Gavin DeGraw/Gavin Degraw - Chariot.mp3
+C:/Users/Rik/Music/Various/Gavin DeGraw/Gavin Degraw - Follow Through.mp3
+C:/Users/Rik/Music/Various/Gavin DeGraw/Gavin Degraw - In Love With a Girl.mp3
+C:/Users/Rik/Music/Various/Intwine - Happy.mp3
+C:/Users/Rik/Music/Various/Jaap - Don't Stop Believin'.mp3
+C:/Users/Rik/Music/Various/Jonas Brothers - Burnin' Up.mp3
+C:/Users/Rik/Music/Various/Joshua Radin - I'd Rather Be With You.mp3
+C:/Users/Rik/Music/Various/Kevin Rudolf - Let It Rock.mp3
+C:/Users/Rik/Music/Various/Kid Rock - All Summer Long.mp3
+C:/Users/Rik/Music/Various/Kylie Minogue/Kylie Minogue - All the Lovers.mp3
+C:/Users/Rik/Music/Various/Kylie Minogue/Kylie Minogue - Get Outta My Way.mp3
+C:/Users/Rik/Music/Various/Kylie Minogue/Kylie Minogue - Love At First Sight.mp3
+C:/Users/Rik/Music/Various/Kylie Minogue/Kylie Minogue - Wow.mp3
+C:/Users/Rik/Music/Various/Lenny Kravitz/Lenny Kravitz - Again.mp3
+C:/Users/Rik/Music/Various/Lenny Kravitz/Lenny Kravitz - Fly Away.mp3
+C:/Users/Rik/Music/Various/Liquido - Narcotic.mp3
+C:/Users/Rik/Music/Various/Live/Live - Heaven.mp3
+C:/Users/Rik/Music/Various/Live/Live - Overcome.mp3
+C:/Users/Rik/Music/Various/Live/Live - Run to the Water.mp3
+C:/Users/Rik/Music/Various/Live/Live - Selling the Drama.mp3
+C:/Users/Rik/Music/Various/Live/Live - The River.mp3
+C:/Users/Rik/Music/Various/Mando Diao - Dance With Somebody.mp3
+C:/Users/Rik/Music/Various/Maroon 5/Maroon 5 - Misery.mp3
+C:/Users/Rik/Music/Various/Maroon 5/Maroon 5 - Won't Go Home Without You.mp3
+C:/Users/Rik/Music/Various/Melee/Melee - Built to Last.mp3
+C:/Users/Rik/Music/Various/Melee/Melee - Imitation.mp3
+C:/Users/Rik/Music/Various/Mike Posner - Cooler Than Me.mp3
+C:/Users/Rik/Music/Various/Novastar/Novastar - Because.mp3
+C:/Users/Rik/Music/Various/Novastar/Novastar - Waiting So Long.mp3
+C:/Users/Rik/Music/Various/Oasis - Wonderwall.mp3
+C:/Users/Rik/Music/Various/One Night Only - Just For Tonight.mp3
+C:/Users/Rik/Music/Various/Robyn - With Every Heartbeat.mp3
+C:/Users/Rik/Music/Various/Roxette/Roxette - How Do You Do!.mp3
+C:/Users/Rik/Music/Various/Roxette/Roxette - It Must Have Been Love.mp3
+C:/Users/Rik/Music/Various/Roxette/Roxette - Joyride.mp3
+C:/Users/Rik/Music/Various/Roxette/Roxette - Listen to Your Heart.mp3
+C:/Users/Rik/Music/Various/Roxette/Roxette - The Look.mp3
+C:/Users/Rik/Music/Various/Scissor Sisters - Fire With Fire.mp3
+C:/Users/Rik/Music/Various/Scouting For Girls - Take a Change On Us.mp3
+C:/Users/Rik/Music/Various/Scouting for Girls/Scouting For Girls - Famous.mp3
+C:/Users/Rik/Music/Various/Scouting for Girls/Scouting For Girls - This Ain't a Love Song.mp3
+C:/Users/Rik/Music/Various/September/September - Can't Get Over.mp3
+C:/Users/Rik/Music/Various/September/September - Cry For You.mp3
+C:/Users/Rik/Music/Various/Sick Puppies - Maybe.mp3
+C:/Users/Rik/Music/Various/Simple Minds - Don't You (Forget About Me).mp3
+C:/Users/Rik/Music/Various/Spin Doctors - Two Princes.mp3
+C:/Users/Rik/Music/Various/Swedish House Mafia - One (Your Name).mp3
+C:/Users/Rik/Music/Various/Taio Cruz - Break Your Heart.mp3
+C:/Users/Rik/Music/Various/The Calling - Wherever You Will Go.mp3
+C:/Users/Rik/Music/Various/The Naked & Famous - Young Blood.mp3
+C:/Users/Rik/Music/Various/The Rasmus - In the Shadows.mp3
+C:/Users/Rik/Music/Various/Train/Train - Drops of Jupiter.mp3
+C:/Users/Rik/Music/Various/Train/Train - Hey, Soul Sister.mp3
+C:/Users/Rik/Music/Various/Train/Train - If It's Love.mp3
+C:/Users/Rik/Music/Various/Wheatus - Teenage Dirtbag.mp3
+C:/Users/Rik/Music/Various/Within Temptation - Faster.mp3
+C:/Users/Rik/Music/Various/Jason Derulo - In My Head.mp3
+C:/Users/Rik/Music/Artists/Foo Fighters/Wasting Light/Foo Fighters - Better Off.mp3
+C:/Users/Rik/Music/Artists/Foo Fighters/Wasting Light/Foo Fighters - I Should Have Known.mp3
+C:/Users/Rik/Music/Artists/Jimmy Eat World/Chase The Light/Jimmy Eat World - Always Be.mp3
+C:/Users/Rik/Music/Artists/Jimmy Eat World/Chase The Light/Jimmy Eat World - Big Casino.mp3
+C:/Users/Rik/Music/Artists/Jimmy Eat World/Chase The Light/Jimmy Eat World - Carry You.mp3
+C:/Users/Rik/Music/Artists/Jimmy Eat World/Chase The Light/Jimmy Eat World - Chase This Light.mp3
+C:/Users/Rik/Music/Artists/Jimmy Eat World/Chase The Light/Jimmy Eat World - Dizzy.mp3
+C:/Users/Rik/Music/Artists/Jimmy Eat World/Chase The Light/Jimmy Eat World - Electable (Give It Up).mp3
+C:/Users/Rik/Music/Artists/Jimmy Eat World/Chase The Light/Jimmy Eat World - Feeling Lucky.mp3
+C:/Users/Rik/Music/Artists/Jimmy Eat World/Chase The Light/Jimmy Eat World - Firefight.mp3
+C:/Users/Rik/Music/Artists/Jimmy Eat World/Chase The Light/Jimmy Eat World - Gotta Be Somebody's Blues.mp3
+C:/Users/Rik/Music/Artists/Jimmy Eat World/Chase The Light/Jimmy Eat World - Here It Goes.mp3
+C:/Users/Rik/Music/Artists/Jimmy Eat World/Chase The Light/Jimmy Eat World - Let It Happen.mp3
+C:/Users/Rik/Music/Artists/Simple Plan/Still Not Getting Any/Simple Plan - Crazy.mp3
+C:/Users/Rik/Music/Artists/Simple Plan/Still Not Getting Any/Simple Plan - Everytime.mp3
+C:/Users/Rik/Music/Artists/Simple Plan/Still Not Getting Any/Simple Plan - Jump.mp3
+C:/Users/Rik/Music/Artists/Simple Plan/Still Not Getting Any/Simple Plan - Me Against The World.mp3
+C:/Users/Rik/Music/Artists/Simple Plan/Still Not Getting Any/Simple Plan - One.mp3
+C:/Users/Rik/Music/Artists/Simple Plan/Still Not Getting Any/Simple Plan - Perfect World.mp3
+C:/Users/Rik/Music/Artists/Simple Plan/Still Not Getting Any/Simple Plan - Promise.mp3
+C:/Users/Rik/Music/Artists/Simple Plan/Still Not Getting Any/Simple Plan - Shut Up.mp3
+C:/Users/Rik/Music/Artists/Simple Plan/Still Not Getting Any/Simple Plan - Thank You.mp3
+C:/Users/Rik/Music/Artists/Simple Plan/Still Not Getting Any/Simple Plan - Untitled.mp3
+C:/Users/Rik/Music/Artists/Simple Plan/Still Not Getting Any/Simple Plan - Welcome To My Life.mp3
+C:/Users/Rik/Music/Artists/Volbeat/Beyond Hell-Above Heaven/Volbeat - 16 Dollars.mp3
+C:/Users/Rik/Music/Artists/Volbeat/Beyond Hell-Above Heaven/Volbeat - 7 Shots.mp3
+C:/Users/Rik/Music/Artists/Volbeat/Beyond Hell-Above Heaven/Volbeat - A Better Believer.mp3
+C:/Users/Rik/Music/Artists/Volbeat/Beyond Hell-Above Heaven/Volbeat - A New Day.mp3
+C:/Users/Rik/Music/Artists/Volbeat/Beyond Hell-Above Heaven/Volbeat - A Warrior's Call.mp3
+C:/Users/Rik/Music/Artists/Volbeat/Beyond Hell-Above Heaven/Volbeat - Being 1.mp3
+C:/Users/Rik/Music/Artists/Volbeat/Beyond Hell-Above Heaven/Volbeat - Fallen.mp3
+C:/Users/Rik/Music/Artists/Volbeat/Beyond Hell-Above Heaven/Volbeat - Heaven Nor Hell.mp3
+C:/Users/Rik/Music/Artists/Volbeat/Beyond Hell-Above Heaven/Volbeat - Magic Zone.mp3
+C:/Users/Rik/Music/Artists/Volbeat/Beyond Hell-Above Heaven/Volbeat - Thanks.mp3
+C:/Users/Rik/Music/Artists/Volbeat/Beyond Hell-Above Heaven/Volbeat - The Mirror and the Ripper.mp3
+C:/Users/Rik/Music/Artists/Volbeat/Beyond Hell-Above Heaven/Volbeat - Who They Are.mp3
+C:/Users/Rik/Music/Various/Beady Eye - The Roller.mp3
+C:/Users/Rik/Music/Various/Depeche Mode - Just Can't Get Enough.mp3
+C:/Users/Rik/Music/Various/Kelly Clarkson/Kelly Clarkson - Because of You.mp3
+C:/Users/Rik/Music/Various/Kelly Clarkson/Kelly Clarkson - Behind These Hazel Eyes.mp3
+C:/Users/Rik/Music/Various/Kelly Clarkson/Kelly Clarkson - Since U Been Gone.mp3
+C:/Users/Rik/Music/Artists/The Gaslight Anthem/American Slang/The Gaslight Anthem - American Slang.mp3
+C:/Users/Rik/Music/Artists/The Gaslight Anthem/American Slang/The Gaslight Anthem - Boxer.mp3
+C:/Users/Rik/Music/Artists/The Gaslight Anthem/American Slang/The Gaslight Anthem - Bring It On.mp3
+C:/Users/Rik/Music/Artists/The Gaslight Anthem/American Slang/The Gaslight Anthem - Old Haunts.mp3
+C:/Users/Rik/Music/Artists/The Gaslight Anthem/American Slang/The Gaslight Anthem - Orphans.mp3
+C:/Users/Rik/Music/Artists/The Gaslight Anthem/American Slang/The Gaslight Anthem - Stay Lucky.mp3
+C:/Users/Rik/Music/Artists/The Gaslight Anthem/American Slang/The Gaslight Anthem - The Diamond Church Street Choir.mp3
+C:/Users/Rik/Music/Artists/The Gaslight Anthem/American Slang/The Gaslight Anthem - The Queen Of Lower Chelsea.mp3
+C:/Users/Rik/Music/Artists/The Gaslight Anthem/American Slang/The Gaslight Anthem - The Spirit Of Jazz.mp3
+C:/Users/Rik/Music/Artists/The Gaslight Anthem/American Slang/The Gaslight Anthem - We Did It When We Were Young.mp3
+C:/Users/Rik/Music/Artists/Blind/Blind/Blind - Break Away.mp3
+C:/Users/Rik/Music/Artists/Blind/Blind/Blind - Every You Every Me.mp3
+C:/Users/Rik/Music/Artists/Blind/Blind/Blind - Jesus Only Knows.mp3
+C:/Users/Rik/Music/Artists/Blind/Blind/Blind - Love Is Gone.mp3
+C:/Users/Rik/Music/Artists/Blind/Blind/Blind - Ordinary Day.mp3
+C:/Users/Rik/Music/Artists/Blind/Blind/Blind - People.mp3
+C:/Users/Rik/Music/Artists/Blind/Blind/Blind - Save Me Now.mp3
+C:/Users/Rik/Music/Artists/Blind/Blind/Blind - These Are the Days.mp3
+C:/Users/Rik/Music/Artists/Blind/Blind/Blind - Today I Break Loose.mp3
+C:/Users/Rik/Music/Artists/Blind/Blind/Blind - Triple X.mp3
+C:/Users/Rik/Music/Artists/Blind/Blind/Blind - Wake Me Up.mp3
+C:/Users/Rik/Music/Artists/Blind/Blind/Blind - We Can Stay.mp3
+C:/Users/Rik/Music/Artists/Blind/Blind/Blind - You.mp3
+C:/Users/Rik/Music/Artists/Cute Is What We Aim For/Rotation/Cute Is What We Aim For - Do What You Do.mp3
+C:/Users/Rik/Music/Artists/Cute Is What We Aim For/Rotation/Cute Is What We Aim For - Doctor.mp3
+C:/Users/Rik/Music/Artists/Cute Is What We Aim For/Rotation/Cute Is What We Aim For - Hollywood.mp3
+C:/Users/Rik/Music/Artists/Cute Is What We Aim For/Rotation/Cute Is What We Aim For - Loser.mp3
+C:/Users/Rik/Music/Artists/Cute Is What We Aim For/Rotation/Cute Is What We Aim For - Marriage to Millions.mp3
+C:/Users/Rik/Music/Artists/Cute Is What We Aim For/Rotation/Cute Is What We Aim For - Miss Sobriety.mp3
+C:/Users/Rik/Music/Artists/Cute Is What We Aim For/Rotation/Cute Is What We Aim For - Navigate Me.mp3
+C:/Users/Rik/Music/Artists/Cute Is What We Aim For/Rotation/Cute Is What We Aim For - Practice Makes Perfect.mp3
+C:/Users/Rik/Music/Artists/Cute Is What We Aim For/Rotation/Cute Is What We Aim For - Safe Ride.mp3
+C:/Users/Rik/Music/Artists/Cute Is What We Aim For/Rotation/Cute Is What We Aim For - The Lock Down Denial.mp3
+C:/Users/Rik/Music/Artists/Cute Is What We Aim For/Rotation/Cute Is What We Aim For - Time.mp3
+C:/Users/Rik/Music/Artists/Kids In Glass Houses/Dirt/Kids In Glass Houses - Artbreaker I.mp3
+C:/Users/Rik/Music/Artists/Kids In Glass Houses/Dirt/Kids In Glass Houses - Artbreaker II.mp3
+C:/Users/Rik/Music/Artists/Kids In Glass Houses/Dirt/Kids In Glass Houses - For Better Or Hearse.mp3
+C:/Users/Rik/Music/Artists/Kids In Glass Houses/Dirt/Kids In Glass Houses - Giving Up.mp3
+C:/Users/Rik/Music/Artists/Kids In Glass Houses/Dirt/Kids In Glass Houses - Hunt the Haunted.mp3
+C:/Users/Rik/Music/Artists/Kids In Glass Houses/Dirt/Kids In Glass Houses - Lilli Rose.mp3
+C:/Users/Rik/Music/Artists/Kids In Glass Houses/Dirt/Kids In Glass Houses - Matters At All.mp3
+C:/Users/Rik/Music/Artists/Kids In Glass Houses/Dirt/Kids In Glass Houses - Maybe Tomorrow.mp3
+C:/Users/Rik/Music/Artists/Kids In Glass Houses/Dirt/Kids In Glass Houses - Sunshine.mp3
+C:/Users/Rik/Music/Artists/Kids In Glass Houses/Dirt/Kids In Glass Houses - The Best Is Yet To Come.mp3
+C:/Users/Rik/Music/Artists/Kids In Glass Houses/Dirt/Kids In Glass Houses - The Morning Afterlife.mp3
+C:/Users/Rik/Music/Artists/Kids In Glass Houses/Dirt/Kids In Glass Houses - Undercover Lover.mp3
+C:/Users/Rik/Music/Artists/Kids In Glass Houses/Dirt/Kids In Glass Houses - Youngblood (Let It Out).mp3
+C:/Users/Rik/Music/Artists/Simple Plan/Get Your Heart On!/Simple Plan - Anywhere Else But Here.mp3
+C:/Users/Rik/Music/Artists/Simple Plan/Get Your Heart On!/Simple Plan - Astronaut.mp3
+C:/Users/Rik/Music/Artists/Simple Plan/Get Your Heart On!/Simple Plan - Can't Keep My Hands Off You.mp3
+C:/Users/Rik/Music/Artists/Simple Plan/Get Your Heart On!/Simple Plan - Freaking Me Out.mp3
+C:/Users/Rik/Music/Artists/Simple Plan/Get Your Heart On!/Simple Plan - Gone Too Soon.mp3
+C:/Users/Rik/Music/Artists/Simple Plan/Get Your Heart On!/Simple Plan - Jet Lag.mp3
+C:/Users/Rik/Music/Artists/Simple Plan/Get Your Heart On!/Simple Plan - Last One Standing.mp3
+C:/Users/Rik/Music/Artists/Simple Plan/Get Your Heart On!/Simple Plan - Loser Of The Year.mp3
+C:/Users/Rik/Music/Artists/Simple Plan/Get Your Heart On!/Simple Plan - This Song Saved My Life.mp3
+C:/Users/Rik/Music/Artists/Simple Plan/Get Your Heart On!/Simple Plan - You Suck At Love.mp3
+C:/Users/Rik/Music/Various/The Von Bondies - C%60Mon C%60Mon.mp3
+C:/Users/Rik/Music/Various/White Stripes - Seven Nation Army.mp3
+C:/Users/Rik/Music/Artists/Futures/The Holiday/Futures - 16.mp3
+C:/Users/Rik/Music/Artists/Futures/The Holiday/Futures - Holiday.mp3
+C:/Users/Rik/Music/Artists/Futures/The Holiday/Futures - Sal Paradise.mp3
+C:/Users/Rik/Music/Artists/Futures/The Holiday/Futures - Take Me Home.mp3
+C:/Users/Rik/Music/Artists/Futures/The Holiday/Futures - Thank You.mp3
+C:/Users/Rik/Music/Artists/Futures/The Holiday/Futures - The Boy Who Cried Wolf.mp3
+C:/Users/Rik/Music/Artists/Futures/The Holiday/Futures - The Summer.mp3
+C:/Users/Rik/Music/Artists/Rise Against/Appeal To Reason/Rise Against - Audience of One.mp3
+C:/Users/Rik/Music/Artists/Rise Against/Appeal To Reason/Rise Against - Collapse (Post-Amerika).mp3
+C:/Users/Rik/Music/Artists/Rise Against/Appeal To Reason/Rise Against - Elective Amnesia.mp3
+C:/Users/Rik/Music/Artists/Rise Against/Appeal To Reason/Rise Against - Entertainment.mp3
+C:/Users/Rik/Music/Artists/Rise Against/Appeal To Reason/Rise Against - From Heads Unworthy.mp3
+C:/Users/Rik/Music/Artists/Rise Against/Appeal To Reason/Rise Against - Hairline Fracture.mp3
+C:/Users/Rik/Music/Artists/Rise Against/Appeal To Reason/Rise Against - Hero of War.mp3
+C:/Users/Rik/Music/Artists/Rise Against/Appeal To Reason/Rise Against - Kotov Syndrome.mp3
+C:/Users/Rik/Music/Artists/Rise Against/Appeal To Reason/Rise Against - Long Forgotten Sons.mp3
+C:/Users/Rik/Music/Artists/Rise Against/Appeal To Reason/Rise Against - Prayer of the Refugee.mp3
+C:/Users/Rik/Music/Artists/Rise Against/Appeal To Reason/Rise Against - Re-Education (Through Labor).mp3
+C:/Users/Rik/Music/Artists/Rise Against/Appeal To Reason/Rise Against - Savior.mp3
+C:/Users/Rik/Music/Artists/Rise Against/Appeal To Reason/Rise Against - The Dirt Whispered.mp3
+C:/Users/Rik/Music/Artists/Rise Against/Appeal To Reason/Rise Against - The Strength to Go On.mp3
+C:/Users/Rik/Music/Artists/Rise Against/Appeal To Reason/Rise Against - Whereabouts Unknown.mp3
+C:/Users/Rik/Music/Artists/White Lies/To Lose My Life/White Lies - A Place To Hide.mp3
+C:/Users/Rik/Music/Artists/White Lies/To Lose My Life/White Lies - Death.mp3
+C:/Users/Rik/Music/Artists/White Lies/To Lose My Life/White Lies - E.S.T..mp3
+C:/Users/Rik/Music/Artists/White Lies/To Lose My Life/White Lies - Farewell To The Fairground.mp3
+C:/Users/Rik/Music/Artists/White Lies/To Lose My Life/White Lies - Fifty On Our Foreheads.mp3
+C:/Users/Rik/Music/Artists/White Lies/To Lose My Life/White Lies - From The Stars.mp3
+C:/Users/Rik/Music/Artists/White Lies/To Lose My Life/White Lies - Nothing To Give.mp3
+C:/Users/Rik/Music/Artists/White Lies/To Lose My Life/White Lies - The Price Of Love.mp3
+C:/Users/Rik/Music/Artists/White Lies/To Lose My Life/White Lies - To Lose My Life.mp3
+C:/Users/Rik/Music/Artists/White Lies/To Lose My Life/White Lies - Unfinished Business.mp3
+C:/Users/Rik/Music/Artists/Yellowcard/When You're Through Thinking, Say Yes/Yellowcard - Be the Young.mp3
+C:/Users/Rik/Music/Artists/Yellowcard/When You're Through Thinking, Say Yes/Yellowcard - For You and Your Denial.mp3
+C:/Users/Rik/Music/Artists/Yellowcard/When You're Through Thinking, Say Yes/Yellowcard - Hang You Up.mp3
+C:/Users/Rik/Music/Artists/Yellowcard/When You're Through Thinking, Say Yes/Yellowcard - Hide.mp3
+C:/Users/Rik/Music/Artists/Yellowcard/When You're Through Thinking, Say Yes/Yellowcard - Life of Leaving Home.mp3
+C:/Users/Rik/Music/Artists/Yellowcard/When You're Through Thinking, Say Yes/Yellowcard - Promises.mp3
+C:/Users/Rik/Music/Artists/Yellowcard/When You're Through Thinking, Say Yes/Yellowcard - See Me Smiling.mp3
+C:/Users/Rik/Music/Artists/Yellowcard/When You're Through Thinking, Say Yes/Yellowcard - Sing for Me (Acoustic).mp3
+C:/Users/Rik/Music/Artists/Yellowcard/When You're Through Thinking, Say Yes/Yellowcard - Sing for Me.mp3
+C:/Users/Rik/Music/Artists/Yellowcard/When You're Through Thinking, Say Yes/Yellowcard - Soundtrack.mp3
+C:/Users/Rik/Music/Artists/Yellowcard/When You're Through Thinking, Say Yes/Yellowcard - The Sound of You and Me.mp3
+C:/Users/Rik/Music/Artists/Yellowcard/When You're Through Thinking, Say Yes/Yellowcard - With You Around.mp3
+C:/Users/Rik/Music/Artists/Fall Out Boy/Infinity On High/Fall Out Boy - Bang The Doldrums.mp3
+C:/Users/Rik/Music/Artists/Fall Out Boy/Infinity On High/Fall Out Boy - Don't You Know Who I Think I Am.mp3
+C:/Users/Rik/Music/Artists/Fall Out Boy/Infinity On High/Fall Out Boy - Fame.mp3
+C:/Users/Rik/Music/Artists/Fall Out Boy/Infinity On High/Fall Out Boy - Hum Hallelujah.mp3
+C:/Users/Rik/Music/Artists/Fall Out Boy/Infinity On High/Fall Out Boy - I'm Like A Lawyer With The Way I'm Always Trying To Get You Off (me+you).mp3
+C:/Users/Rik/Music/Artists/Fall Out Boy/Infinity On High/Fall Out Boy - I've Got All This Ringing In My Ears And None On My Fingers.mp3
+C:/Users/Rik/Music/Artists/Fall Out Boy/Infinity On High/Fall Out Boy - Thanks For The Memories.mp3
+C:/Users/Rik/Music/Artists/Fall Out Boy/Infinity On High/Fall Out Boy - The (After) Life Of The Party.mp3
+C:/Users/Rik/Music/Artists/Fall Out Boy/Infinity On High/Fall Out Boy - The Carpal Tunnel Of Love.mp3
+C:/Users/Rik/Music/Artists/Fall Out Boy/Infinity On High/Fall Out Boy - The Take Over, The Breaks Over.mp3
+C:/Users/Rik/Music/Artists/Fall Out Boy/Infinity On High/Fall Out Boy - This Ain't A Scene, It's An Arms Race.mp3
+C:/Users/Rik/Music/Artists/Fall Out Boy/Infinity On High/Fall Out Boy - Thriller.mp3
+C:/Users/Rik/Music/Artists/Fall Out Boy/Infinity On High/Fall Out Boy - You're Crashing, But You're No Wave.mp3
+C:/Users/Rik/Music/Artists/Jimmy Eat World/Invented/Jimmy Eat World - Action Needs An Audience.mp3
+C:/Users/Rik/Music/Artists/Jimmy Eat World/Invented/Jimmy Eat World - Coffee And Cigarettes.mp3
+C:/Users/Rik/Music/Artists/Jimmy Eat World/Invented/Jimmy Eat World - Cut.mp3
+C:/Users/Rik/Music/Artists/Jimmy Eat World/Invented/Jimmy Eat World - Evidence.mp3
+C:/Users/Rik/Music/Artists/Jimmy Eat World/Invented/Jimmy Eat World - Heart Is Hard To Find.mp3
+C:/Users/Rik/Music/Artists/Jimmy Eat World/Invented/Jimmy Eat World - Higher Devotion.mp3
+C:/Users/Rik/Music/Artists/Jimmy Eat World/Invented/Jimmy Eat World - Invented.mp3
+C:/Users/Rik/Music/Artists/Jimmy Eat World/Invented/Jimmy Eat World - Littlething.mp3
+C:/Users/Rik/Music/Artists/Jimmy Eat World/Invented/Jimmy Eat World - Mixtape.mp3
+C:/Users/Rik/Music/Artists/Jimmy Eat World/Invented/Jimmy Eat World - Movielike.mp3
+C:/Users/Rik/Music/Artists/Jimmy Eat World/Invented/Jimmy Eat World - My Best Theory.mp3
+C:/Users/Rik/Music/Artists/Jimmy Eat World/Invented/Jimmy Eat World - Stop.mp3
+C:/Users/Rik/Music/Artists/Red/Until We Have Faces/Red - Best Is Yet to Come.mp3
+C:/Users/Rik/Music/Artists/Red/Until We Have Faces/Red - Buried Beneath.mp3
+C:/Users/Rik/Music/Artists/Red/Until We Have Faces/Red - Faceless.mp3
+C:/Users/Rik/Music/Artists/Red/Until We Have Faces/Red - Feed the Machine.mp3
+C:/Users/Rik/Music/Artists/Red/Until We Have Faces/Red - Hymn for the Missing.mp3
+C:/Users/Rik/Music/Artists/Red/Until We Have Faces/Red - Let It Burn.mp3
+C:/Users/Rik/Music/Artists/Red/Until We Have Faces/Red - Lie to Me (Denial).mp3
+C:/Users/Rik/Music/Artists/Red/Until We Have Faces/Red - Not Alone.mp3
+C:/Users/Rik/Music/Artists/Red/Until We Have Faces/Red - The Outside.mp3
+C:/Users/Rik/Music/Artists/Red/Until We Have Faces/Red - Watch You Crawl.mp3
+C:/Users/Rik/Music/Artists/Red/Until We Have Faces/Red - Who We Are.mp3
+C:/Users/Rik/Music/Artists/Framing Hanley/A Promise To Burn/Framing Hanley - Back To Go Again.mp3
+C:/Users/Rik/Music/Artists/Framing Hanley/A Promise To Burn/Framing Hanley - Bittersweet Sundown.mp3
+C:/Users/Rik/Music/Artists/Framing Hanley/A Promise To Burn/Framing Hanley - Fool With Dreams.mp3
+C:/Users/Rik/Music/Artists/Framing Hanley/A Promise To Burn/Framing Hanley - Intro.mp3
+C:/Users/Rik/Music/Artists/Framing Hanley/A Promise To Burn/Framing Hanley - Livin' So Divine.mp3
+C:/Users/Rik/Music/Artists/Framing Hanley/A Promise To Burn/Framing Hanley - Photographs & Gasoline.mp3
+C:/Users/Rik/Music/Artists/Framing Hanley/A Promise To Burn/Framing Hanley - The Burn.mp3
+C:/Users/Rik/Music/Artists/Framing Hanley/A Promise To Burn/Framing Hanley - The Promise.mp3
+C:/Users/Rik/Music/Artists/Framing Hanley/A Promise To Burn/Framing Hanley - Wake Up.mp3
+C:/Users/Rik/Music/Artists/Framing Hanley/A Promise To Burn/Framing Hanley - WarZone.mp3
+C:/Users/Rik/Music/Artists/Framing Hanley/A Promise To Burn/Framing Hanley - Weight of The World.mp3
+C:/Users/Rik/Music/Artists/Framing Hanley/A Promise To Burn/Framing Hanley - You Stupid Girl.mp3
+C:/Users/Rik/Music/Artists/Framing Hanley/A Promise To Burn/Framing Hanley - You.mp3
+C:/Users/Rik/Music/Artists/Anberlin/Cities/Anberlin - (Fin).mp3
+C:/Users/Rik/Music/Artists/Anberlin/Cities/Anberlin - A Whisper & A Clamour.mp3
+C:/Users/Rik/Music/Artists/Anberlin/Cities/Anberlin - Adelaide.mp3
+C:/Users/Rik/Music/Artists/Anberlin/Cities/Anberlin - Alexithymia.mp3
+C:/Users/Rik/Music/Artists/Anberlin/Cities/Anberlin - Debut.mp3
+C:/Users/Rik/Music/Artists/Anberlin/Cities/Anberlin - Dismantle. Repair.mp3
+C:/Users/Rik/Music/Artists/Anberlin/Cities/Anberlin - Godspeed.mp3
+C:/Users/Rik/Music/Artists/Anberlin/Cities/Anberlin - Hello Alone.mp3
+C:/Users/Rik/Music/Artists/Anberlin/Cities/Anberlin - Inevitable.mp3
+C:/Users/Rik/Music/Artists/Anberlin/Cities/Anberlin - Reclusion.mp3
+C:/Users/Rik/Music/Artists/Anberlin/Cities/Anberlin - The Promise.mp3
+C:/Users/Rik/Music/Artists/Anberlin/Cities/Anberlin - The Unwinding Cable Car.mp3
+C:/Users/Rik/Music/Artists/Anberlin/Cities/Anberlin - There Is A Light That Never Goes Dope.mp3
+C:/Users/Rik/Music/Artists/Anberlin/Cities/Anberlin - There Is No Mathematics To Love And Loss.mp3
+C:/Users/Rik/Music/Artists/Anberlin/Cities/Anberlin - Uncanny.mp3
+C:/Users/Rik/Music/Artists/Anberlin/New Surrender/Anberlin - Blame Me! Blame Me!.mp3
+C:/Users/Rik/Music/Artists/Anberlin/New Surrender/Anberlin - Breaking.mp3
+C:/Users/Rik/Music/Artists/Anberlin/New Surrender/Anberlin - Breathe.mp3
+C:/Users/Rik/Music/Artists/Anberlin/New Surrender/Anberlin - Burn Out Brighter (Northern Lights).mp3
+C:/Users/Rik/Music/Artists/Anberlin/New Surrender/Anberlin - Disappear.mp3
+C:/Users/Rik/Music/Artists/Anberlin/New Surrender/Anberlin - Feel Good Drag.mp3
+C:/Users/Rik/Music/Artists/Anberlin/New Surrender/Anberlin - Haight St.mp3
+C:/Users/Rik/Music/Artists/Anberlin/New Surrender/Anberlin - Misearbile Visu (Ex Malo Bonum).mp3
+C:/Users/Rik/Music/Artists/Anberlin/New Surrender/Anberlin - Retrace.mp3
+C:/Users/Rik/Music/Artists/Anberlin/New Surrender/Anberlin - Soft Skeletons.mp3
+C:/Users/Rik/Music/Artists/Anberlin/New Surrender/Anberlin - The Resistance.mp3
+C:/Users/Rik/Music/Artists/Anberlin/New Surrender/Anberlin - Younglife.mp3
+C:/Users/Rik/Music/Artists/Arcade Fire/Neon Bible/Arcade Fire - Antichrist Television Blues.mp3
+C:/Users/Rik/Music/Artists/Arcade Fire/Neon Bible/Arcade Fire - Black Mirror.mp3
+C:/Users/Rik/Music/Artists/Arcade Fire/Neon Bible/Arcade Fire - Black WaveBad Vibrations.mp3
+C:/Users/Rik/Music/Artists/Arcade Fire/Neon Bible/Arcade Fire - Intervention.mp3
+C:/Users/Rik/Music/Artists/Arcade Fire/Neon Bible/Arcade Fire - Keep The Car Running.mp3
+C:/Users/Rik/Music/Artists/Arcade Fire/Neon Bible/Arcade Fire - No Cars Go.mp3
+C:/Users/Rik/Music/Artists/Arcade Fire/Neon Bible/Arcade Fire - Ocean Of Noise.mp3
+C:/Users/Rik/Music/Artists/Arcade Fire/Neon Bible/Arcade Fire - Well & The Lighthouse, The.mp3
+C:/Users/Rik/Music/Artists/Arcade Fire/Neon Bible/Arcade Fire - Windowsill.mp3
+C:/Users/Rik/Music/Artists/Green Day/21st Century Breakdown/Green Day - %C2%A1Viva la Gloria!.mp3
+C:/Users/Rik/Music/Artists/The Gaslight Anthem/Sink or Swim/The Gaslight Anthem - 1990.mp3
+C:/Users/Rik/Music/Artists/The Gaslight Anthem/Sink or Swim/The Gaslight Anthem - Angry Johnny and the Radio.mp3
+C:/Users/Rik/Music/Artists/The Gaslight Anthem/Sink or Swim/The Gaslight Anthem - Bomboxes and Dictionaries.mp3
+C:/Users/Rik/Music/Artists/The Gaslight Anthem/Sink or Swim/The Gaslight Anthem - Drive.mp3
+C:/Users/Rik/Music/Artists/The Gaslight Anthem/Sink or Swim/The Gaslight Anthem - I Coul'da Been a Contender.mp3
+C:/Users/Rik/Music/Artists/The Gaslight Anthem/Sink or Swim/The Gaslight Anthem - I'da Called You Woody, Joe.mp3
+C:/Users/Rik/Music/Artists/The Gaslight Anthem/Sink or Swim/The Gaslight Anthem - Red in the Morning.mp3
+C:/Users/Rik/Music/Artists/The Gaslight Anthem/Sink or Swim/The Gaslight Anthem - We Came to Dance.mp3
+C:/Users/Rik/Music/Artists/The Gaslight Anthem/Sink or Swim/The Gaslight Anthem - We're Getting A Divorce, You Keep The Dinner.mp3
+C:/Users/Rik/Music/Artists/The Gaslight Anthem/Sink or Swim/The Gaslight Anthem - Wooderson.mp3
+C:/Users/Rik/Music/Artists/Volbeat/Guitar Gangsters & Cadillac Blood/Volbeat - Back To Prom.mp3
+C:/Users/Rik/Music/Artists/Volbeat/Guitar Gangsters & Cadillac Blood/Volbeat - Broken Man And The Dawn.mp3
+C:/Users/Rik/Music/Artists/Volbeat/Guitar Gangsters & Cadillac Blood/Volbeat - End Of The Road.mp3
+C:/Users/Rik/Music/Artists/Volbeat/Guitar Gangsters & Cadillac Blood/Volbeat - Find That Soul.mp3
+C:/Users/Rik/Music/Artists/Volbeat/Guitar Gangsters & Cadillac Blood/Volbeat - Guitar Gangsters & Cadillac Blood.mp3
+C:/Users/Rik/Music/Artists/Volbeat/Guitar Gangsters & Cadillac Blood/Volbeat - Hallelujah Goat.mp3
+C:/Users/Rik/Music/Artists/Volbeat/Guitar Gangsters & Cadillac Blood/Volbeat - I'm So Lonesome I Could Cry.mp3
+C:/Users/Rik/Music/Artists/Volbeat/Guitar Gangsters & Cadillac Blood/Volbeat - Light A Way.mp3
+C:/Users/Rik/Music/Artists/Volbeat/Guitar Gangsters & Cadillac Blood/Volbeat - Making Believe.mp3
+C:/Users/Rik/Music/Artists/Volbeat/Guitar Gangsters & Cadillac Blood/Volbeat - Mary Ann' s Place.mp3
+C:/Users/Rik/Music/Artists/Volbeat/Guitar Gangsters & Cadillac Blood/Volbeat - Maybellene I Hofteholder.mp3
+C:/Users/Rik/Music/Artists/Volbeat/Guitar Gangsters & Cadillac Blood/Volbeat - Still Counting.mp3
+C:/Users/Rik/Music/Artists/Volbeat/Guitar Gangsters & Cadillac Blood/Volbeat - We.mp3
+C:/Users/Rik/Music/Artists/Volbeat/Guitar Gangsters & Cadillac Blood/Volbeat - Wild Rover Of Hell.mp3
+C:/Users/Rik/Music/Artists/My Chemical Romance/Danger Days - The True Lives Of The Fabulous Killjoys/My Chemical Romance - Bulletproof Heart.mp3
+C:/Users/Rik/Music/Artists/My Chemical Romance/Danger Days - The True Lives Of The Fabulous Killjoys/My Chemical Romance - Destroya.mp3
+C:/Users/Rik/Music/Artists/My Chemical Romance/Danger Days - The True Lives Of The Fabulous Killjoys/My Chemical Romance - Party Poison.mp3
+C:/Users/Rik/Music/Artists/My Chemical Romance/Danger Days - The True Lives Of The Fabulous Killjoys/My Chemical Romance - Planetary (Go!).mp3
+C:/Users/Rik/Music/Artists/My Chemical Romance/Danger Days - The True Lives Of The Fabulous Killjoys/My Chemical Romance - Save Yourself- I'll Hold Them Back.mp3
+C:/Users/Rik/Music/Artists/My Chemical Romance/Danger Days - The True Lives Of The Fabulous Killjoys/My Chemical Romance - S-C-A-R-E-C-R-O-W.mp3
+C:/Users/Rik/Music/Artists/My Chemical Romance/Danger Days - The True Lives Of The Fabulous Killjoys/My Chemical Romance - Sing.mp3
+C:/Users/Rik/Music/Artists/My Chemical Romance/Danger Days - The True Lives Of The Fabulous Killjoys/My Chemical Romance - Summertime.mp3
+C:/Users/Rik/Music/Artists/My Chemical Romance/Danger Days - The True Lives Of The Fabulous Killjoys/My Chemical Romance - The Kids From Yesterday.mp3
+C:/Users/Rik/Music/Artists/My Chemical Romance/Danger Days - The True Lives Of The Fabulous Killjoys/My Chemical Romance - The Only Hope For Me Is You.mp3
+C:/Users/Rik/Music/Artists/My Chemical Romance/Danger Days - The True Lives Of The Fabulous Killjoys/My Chemical Romance - Vampire Money.mp3
+C:/Users/Rik/Music/Artists/Longwave/Secrets Are Sinister/Longwave - Eyes Like Headlights.mp3
+C:/Users/Rik/Music/Artists/Longwave/Secrets Are Sinister/Longwave - I Don't Dare.mp3
+C:/Users/Rik/Music/Artists/Longwave/Secrets Are Sinister/Longwave - It's True.mp3
+C:/Users/Rik/Music/Artists/Longwave/Secrets Are Sinister/Longwave - Life Is Wrong.mp3
+C:/Users/Rik/Music/Artists/Longwave/Secrets Are Sinister/Longwave - No Direction.mp3
+C:/Users/Rik/Music/Artists/Longwave/Secrets Are Sinister/Longwave - Satellites.mp3
+C:/Users/Rik/Music/Artists/Longwave/Secrets Are Sinister/Longwave - Secrets Are Sinister.mp3
+C:/Users/Rik/Music/Artists/Longwave/Secrets Are Sinister/Longwave - Shining Hours.mp3
+C:/Users/Rik/Music/Artists/Longwave/Secrets Are Sinister/Longwave - Sideways Sideways Rain.mp3
+C:/Users/Rik/Music/Artists/Longwave/Secrets Are Sinister/Longwave - Sirens In The Deep Sea.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/I'm With You/Red Hot Chili Peppers - Annie Wants a Baby.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/I'm With You/Red Hot Chili Peppers - Brendan's Death Song.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/I'm With You/Red Hot Chili Peppers - Dance, Dance, Dance.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/I'm With You/Red Hot Chili Peppers - Did I Let You Know.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/I'm With You/Red Hot Chili Peppers - Ethiopia.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/I'm With You/Red Hot Chili Peppers - Even You Brutus.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/I'm With You/Red Hot Chili Peppers - Factory of Faith.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/I'm With You/Red Hot Chili Peppers - Goodbye Hooray.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/I'm With You/Red Hot Chili Peppers - Happiness Loves Company.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/I'm With You/Red Hot Chili Peppers - Look Around.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/I'm With You/Red Hot Chili Peppers - Meet Me At the Corner.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/I'm With You/Red Hot Chili Peppers - Monarchy of Roses.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/I'm With You/Red Hot Chili Peppers - Police Station.mp3
+C:/Users/Rik/Music/Artists/Red Hot Chili Peppers/I'm With You/Red Hot Chili Peppers - The Adventures of Rain Dance Maggie.mp3
+C:/Users/Rik/Music/Artists/Amber Pacific/Virtues/Amber Pacific - An Anthem For The Young At Heart.mp3
+C:/Users/Rik/Music/Artists/Amber Pacific/Virtues/Amber Pacific - Burdens Of The Past.mp3
+C:/Users/Rik/Music/Artists/Amber Pacific/Virtues/Amber Pacific - Conviction.mp3
+C:/Users/Rik/Music/Artists/Amber Pacific/Virtues/Amber Pacific - Shine.mp3
+C:/Users/Rik/Music/Artists/Amber Pacific/Virtues/Amber Pacific - Something To Be Said.mp3
+C:/Users/Rik/Music/Artists/Amber Pacific/Virtues/Amber Pacific - The Best Mistake.mp3
+C:/Users/Rik/Music/Artists/Amber Pacific/Virtues/Amber Pacific - The Girl Who Destroys.mp3
+C:/Users/Rik/Music/Artists/Amber Pacific/Virtues/Amber Pacific - The Good Life.mp3
+C:/Users/Rik/Music/Artists/Amber Pacific/Virtues/Amber Pacific - Three Words.mp3
+C:/Users/Rik/Music/Artists/Amber Pacific/Virtues/Amber Pacific - We Can't Fake This.mp3
+C:/Users/Rik/Music/Artists/Amber Pacific/Virtues/Amber Pacific - What Matters Most.mp3
+C:/Users/Rik/Music/Old/Nirvana - Smells Like Teen Spirit.mp3
+C:/Users/Rik/Music/Artists/10 Years Feeding/Feeding the Wolves/10 Years - Don't Fight It.mp3
+C:/Users/Rik/Music/Artists/Cold War Kids/Mine Is Yours/Cold War Kids - Broken Open.mp3
+C:/Users/Rik/Music/Artists/Cold War Kids/Mine Is Yours/Cold War Kids - Bulldozer.mp3
+C:/Users/Rik/Music/Artists/Cold War Kids/Mine Is Yours/Cold War Kids - Cold Toes On The Cold Floor.mp3
+C:/Users/Rik/Music/Artists/Cold War Kids/Mine Is Yours/Cold War Kids - Finally Begin.mp3
+C:/Users/Rik/Music/Artists/Cold War Kids/Mine Is Yours/Cold War Kids - Louder Than Ever.mp3
+C:/Users/Rik/Music/Artists/Cold War Kids/Mine Is Yours/Cold War Kids - Mine Is Yours.mp3
+C:/Users/Rik/Music/Artists/Cold War Kids/Mine Is Yours/Cold War Kids - Out Of The Wilderness.mp3
+C:/Users/Rik/Music/Artists/Cold War Kids/Mine Is Yours/Cold War Kids - Royal Blue.mp3
+C:/Users/Rik/Music/Artists/Cold War Kids/Mine Is Yours/Cold War Kids - Sensitive Kid.mp3
+C:/Users/Rik/Music/Artists/Cold War Kids/Mine Is Yours/Cold War Kids - Skip The Charades.mp3
+C:/Users/Rik/Music/Artists/Sum 41/Screaming Bloody Murder/Sum 41 - We're the Same.mp3
+C:/Users/Rik/Music/Artists/Maximo Park/Our Earthly Pleasures/Maximo Park - A Fortnight's Time.mp3
+C:/Users/Rik/Music/Artists/Maximo Park/Our Earthly Pleasures/Maximo Park - Books From Boxes.mp3
+C:/Users/Rik/Music/Artists/Maximo Park/Our Earthly Pleasures/Maximo Park - By The Monument.mp3
+C:/Users/Rik/Music/Artists/Maximo Park/Our Earthly Pleasures/Maximo Park - Girls Who Play Guitars.mp3
+C:/Users/Rik/Music/Artists/Maximo Park/Our Earthly Pleasures/Maximo Park - Karaoke Plays.mp3
+C:/Users/Rik/Music/Artists/Maximo Park/Our Earthly Pleasures/Maximo Park - Nosebleed.mp3
+C:/Users/Rik/Music/Artists/Maximo Park/Our Earthly Pleasures/Maximo Park - Our Velocity.mp3
+C:/Users/Rik/Music/Artists/Maximo Park/Our Earthly Pleasures/Maximo Park - Parisian Skies.mp3
+C:/Users/Rik/Music/Artists/Maximo Park/Our Earthly Pleasures/Maximo Park - Russian Literature.mp3
+C:/Users/Rik/Music/Artists/Maximo Park/Our Earthly Pleasures/Maximo Park - Sandblasted And Set Free.mp3
+C:/Users/Rik/Music/Artists/Maximo Park/Our Earthly Pleasures/Maximo Park - The Unshockable.mp3
+C:/Users/Rik/Music/Artists/Maximo Park/Our Earthly Pleasures/Maximo Park - Your Urge.mp3
+C:/Users/Rik/Music/Artists/Stereophonics/Keep Calm and Carry On/Stereophonics - 100MPH.mp3
+C:/Users/Rik/Music/Artists/Stereophonics/Keep Calm and Carry On/Stereophonics - Beerbottle.mp3
+C:/Users/Rik/Music/Artists/Stereophonics/Keep Calm and Carry On/Stereophonics - Could You Be The One.mp3
+C:/Users/Rik/Music/Artists/Stereophonics/Keep Calm and Carry On/Stereophonics - I Got Your Number.mp3
+C:/Users/Rik/Music/Artists/Stereophonics/Keep Calm and Carry On/Stereophonics - Innocent.mp3
+C:/Users/Rik/Music/Artists/Stereophonics/Keep Calm and Carry On/Stereophonics - Live 'N' Love.mp3
+C:/Users/Rik/Music/Artists/Stereophonics/Keep Calm and Carry On/Stereophonics - She's Alright.mp3
+C:/Users/Rik/Music/Artists/Stereophonics/Keep Calm and Carry On/Stereophonics - Show Me How.mp3
+C:/Users/Rik/Music/Artists/Stereophonics/Keep Calm and Carry On/Stereophonics - Stuck In A Rut.mp3
+C:/Users/Rik/Music/Artists/Stereophonics/Keep Calm and Carry On/Stereophonics - Trouble.mp3
+C:/Users/Rik/Music/Artists/Stereophonics/Keep Calm and Carry On/Stereophonics - Uppercut.mp3
+C:/Users/Rik/Music/Artists/Stereophonics/Keep Calm and Carry On/Stereophonics - Wonder.mp3
+C:/Users/Rik/Music/Artists/Foo Fighters/Greatest Hits/Foo Fighters - Everlong (Acoustic).mp3
+C:/Users/Rik/Music/Artists/Lifehouse/Smoke & Mirrors/Lifehouse - Everything (Live).mp3
+C:/Users/Rik/Music/Artists/Amber Pacific/Virtues/Amber Pacific - Forever.mp3
+C:/Users/Rik/Music/Artists/Blink-182/Neighborhoods/Blink-182 - After Midnight.mp3
+C:/Users/Rik/Music/Artists/Blink-182/Neighborhoods/Blink-182 - Even If She Falls.mp3
+C:/Users/Rik/Music/Artists/Blink-182/Neighborhoods/Blink-182 - Fighting the Gravity.mp3
+C:/Users/Rik/Music/Artists/Blink-182/Neighborhoods/Blink-182 - Ghost On The Dance Floor.mp3
+C:/Users/Rik/Music/Artists/Blink-182/Neighborhoods/Blink-182 - Heart's All Gone (Interlude).mp3
+C:/Users/Rik/Music/Artists/Blink-182/Neighborhoods/Blink-182 - Heart's All Gone.mp3
+C:/Users/Rik/Music/Artists/Blink-182/Neighborhoods/Blink-182 - Kaleidoscope.mp3
+C:/Users/Rik/Music/Artists/Blink-182/Neighborhoods/Blink-182 - Love Is Dangerous.mp3
+C:/Users/Rik/Music/Artists/Blink-182/Neighborhoods/Blink-182 - Mh 4.18.2011.mp3
+C:/Users/Rik/Music/Artists/Blink-182/Neighborhoods/Blink-182 - Natives.mp3
+C:/Users/Rik/Music/Artists/Blink-182/Neighborhoods/Blink-182 - Snake Charmer.mp3
+C:/Users/Rik/Music/Artists/Blink-182/Neighborhoods/Blink-182 - This Is Home.mp3
+C:/Users/Rik/Music/Artists/Blink-182/Neighborhoods/Blink-182 - Up All Night.mp3
+C:/Users/Rik/Music/Artists/Blink-182/Neighborhoods/Blink-182 - Wishing Well.mp3
+C:/Users/Rik/Music/Artists/Longwave/Secrets Are Sinister/Longwave - The Devil And The Liar.mp3
+C:/Users/Rik/Music/Artists/Kane/Singles Only/Kane - All I Can Do.mp3
+C:/Users/Rik/Music/Artists/Kane/Singles Only/Kane - Believe It.mp3
+C:/Users/Rik/Music/Artists/Kane/Singles Only/Kane - Can You Handle Me.mp3
+C:/Users/Rik/Music/Artists/Kane/Singles Only/Kane - Catwalk Criminal.mp3
+C:/Users/Rik/Music/Artists/Kane/Singles Only/Kane - Damn Those Eyes.mp3
+C:/Users/Rik/Music/Artists/Kane/Singles Only/Kane - Dreamer.mp3
+C:/Users/Rik/Music/Artists/Kane/Singles Only/Kane - Fearless.mp3
+C:/Users/Rik/Music/Artists/Kane/Singles Only/Kane - Hold On to the World.mp3
+C:/Users/Rik/Music/Artists/Kane/Singles Only/Kane - I Will Keep My Head Down.mp3
+C:/Users/Rik/Music/Artists/Kane/Singles Only/Kane - In Over My Head.mp3
+C:/Users/Rik/Music/Artists/Kane/Singles Only/Kane - It's London Calling.mp3
+C:/Users/Rik/Music/Artists/Kane/Singles Only/Kane - Let It Be.mp3
+C:/Users/Rik/Music/Artists/Kane/Singles Only/Kane - Love Over Healing.mp3
+C:/Users/Rik/Music/Artists/Kane/Singles Only/Kane - My Best Wasn't Good Enough.mp3
+C:/Users/Rik/Music/Artists/Kane/Singles Only/Kane - No Surrender.mp3
+C:/Users/Rik/Music/Artists/Kane/Singles Only/Kane - Rain Down On Me.mp3
+C:/Users/Rik/Music/Artists/Kane/Singles Only/Kane - Scream.mp3
+C:/Users/Rik/Music/Artists/Kane/Singles Only/Kane - Shot of a Gun.mp3
+C:/Users/Rik/Music/Artists/Kane/Singles Only/Kane - So Glad You Made It.mp3
+C:/Users/Rik/Music/Artists/Kane/Singles Only/Kane - Something to Say.mp3
+C:/Users/Rik/Music/Artists/Kane/Singles Only/Kane - Wanna Make It Happen.mp3
+C:/Users/Rik/Music/Artists/Kane/Singles Only/Kane - Where Do I Go Now.mp3
+C:/Users/Rik/Music/Artists/Coldplay/Mylo Xyloto/Coldplay - A Hopeful Transmission.mp3
+C:/Users/Rik/Music/Artists/Coldplay/Mylo Xyloto/Coldplay - Charlie Brown.mp3
+C:/Users/Rik/Music/Artists/Coldplay/Mylo Xyloto/Coldplay - Don't Let It Break Your Heart.mp3
+C:/Users/Rik/Music/Artists/Coldplay/Mylo Xyloto/Coldplay - Every Teardrop Is a Waterfall.mp3
+C:/Users/Rik/Music/Artists/Coldplay/Mylo Xyloto/Coldplay - Hurts Like Heaven.mp3
+C:/Users/Rik/Music/Artists/Coldplay/Mylo Xyloto/Coldplay - M.M.I.X..mp3
+C:/Users/Rik/Music/Artists/Coldplay/Mylo Xyloto/Coldplay - Major Minus.mp3
+C:/Users/Rik/Music/Artists/Coldplay/Mylo Xyloto/Coldplay - Mylo Xyloto.mp3
+C:/Users/Rik/Music/Artists/Coldplay/Mylo Xyloto/Coldplay - Paradise.mp3
+C:/Users/Rik/Music/Artists/Coldplay/Mylo Xyloto/Coldplay - Princess of China.mp3
+C:/Users/Rik/Music/Artists/Coldplay/Mylo Xyloto/Coldplay - U.F.O..mp3
+C:/Users/Rik/Music/Artists/Coldplay/Mylo Xyloto/Coldplay - Up in Flames.mp3
+C:/Users/Rik/Music/Artists/Coldplay/Mylo Xyloto/Coldplay - Up with the Birds.mp3
+C:/Users/Rik/Music/Artists/Coldplay/Mylo Xyloto/Coldplay - Us Against the World.mp3
+C:/Users/Rik/Music/Artists/Kane/Singles Only/Kane - High Places.mp3
+C:/Users/Rik/Music/Artists/White Lies/Ritual/White Lies - Bad Love.mp3
+C:/Users/Rik/Music/Artists/White Lies/Ritual/White Lies - Bigger Than Us.mp3
+C:/Users/Rik/Music/Artists/White Lies/Ritual/White Lies - Come Down.mp3
+C:/Users/Rik/Music/Artists/White Lies/Ritual/White Lies - Holy Ghost.mp3
+C:/Users/Rik/Music/Artists/White Lies/Ritual/White Lies - Is Love.mp3
+C:/Users/Rik/Music/Artists/White Lies/Ritual/White Lies - Peace & Quiet.mp3
+C:/Users/Rik/Music/Artists/White Lies/Ritual/White Lies - Strangers.mp3
+C:/Users/Rik/Music/Artists/White Lies/Ritual/White Lies - Streetlights.mp3
+C:/Users/Rik/Music/Artists/White Lies/Ritual/White Lies - The Power & The Glory.mp3
+C:/Users/Rik/Music/Artists/White Lies/Ritual/White Lies - Turn The Bells.mp3
+C:/Users/Rik/Music/Artists/Destine/Destine - Thousand Miles.mp3
+C:/Users/Rik/Music/Artists/The Seer/Heading for the Sun/The Seer - Dive Into The Blue Sky.mp3
+C:/Users/Rik/Music/Artists/The Seer/Heading for the Sun/The Seer - Eyes Gone Blind.mp3
+C:/Users/Rik/Music/Artists/The Seer/Heading for the Sun/The Seer - Fallen Leaves.mp3
+C:/Users/Rik/Music/Artists/The Seer/Heading for the Sun/The Seer - Rain Down On Me.mp3
+C:/Users/Rik/Music/Artists/The Seer/Heading for the Sun/The Seer - Raining.mp3
+C:/Users/Rik/Music/Artists/The Seer/Heading for the Sun/The Seer - Setting Sails.mp3
+C:/Users/Rik/Music/Artists/The Seer/Heading for the Sun/The Seer - The Borderline.mp3
+C:/Users/Rik/Music/Artists/The Seer/Heading for the Sun/The Seer - The Enemy.mp3
+C:/Users/Rik/Music/Artists/The Seer/Heading for the Sun/The Seer - Wasted.mp3
+C:/Users/Rik/Music/Artists/The Seer/Heading for the Sun/The Seer - What We Are.mp3
+C:/Users/Rik/Music/Artists/The Seer/Heading for the Sun/The Seer - Where Do We Go.mp3
+C:/Users/Rik/Music/Artists/The Seer/Heading for the Sun/The Seer - Wishful Thinking.mp3
+C:/Users/Rik/Music/Old/Bruce Springsteen/Bruce Springsteen - The River.mp3
+C:/Users/Rik/Music/Archive/Artists/Snow Patrol/Fallen Empires/Snow Patrol - Called Out In The Dark.mp3
+C:/Users/Rik/Music/Archive/Artists/Snow Patrol/Fallen Empires/Snow Patrol - This Isn't Everything You Are.mp3
+C:/Users/Rik/Music/Archive/Artists/The Wombats/This Modern Glitch/The Wombats - Techno Fan.mp3
+C:/Users/Rik/Music/Archive/Artists/The Wombats/This Modern Glitch/The Wombats - Tokyo (Vampires & Wolves).mp3
+C:/Users/Rik/Music/Artists/The Offspring/Rise and Fall Rage and Grace/The Offspring - A Lot Like Me.mp3
+C:/Users/Rik/Music/Artists/The Offspring/Rise and Fall Rage and Grace/The Offspring - Fix You.mp3
+C:/Users/Rik/Music/Artists/The Offspring/Rise and Fall Rage and Grace/The Offspring - Half-Truism.mp3
+C:/Users/Rik/Music/Artists/The Offspring/Rise and Fall Rage and Grace/The Offspring - Hammerhead.mp3
+C:/Users/Rik/Music/Artists/The Offspring/Rise and Fall Rage and Grace/The Offspring - Kristy, Are You Doing Okay.mp3
+C:/Users/Rik/Music/Artists/The Offspring/Rise and Fall Rage and Grace/The Offspring - Let's Hear It For Rock Bottom.mp3
+C:/Users/Rik/Music/Artists/The Offspring/Rise and Fall Rage and Grace/The Offspring - Nothingtown.mp3
+C:/Users/Rik/Music/Artists/The Offspring/Rise and Fall Rage and Grace/The Offspring - O.C. Life.mp3
+C:/Users/Rik/Music/Artists/The Offspring/Rise and Fall Rage and Grace/The Offspring - Rise And Fall.mp3
+C:/Users/Rik/Music/Artists/The Offspring/Rise and Fall Rage and Grace/The Offspring - Stuff Is Messed Up.mp3
+C:/Users/Rik/Music/Artists/The Offspring/Rise and Fall Rage and Grace/The Offspring - Takes Me Nowhere.mp3
+C:/Users/Rik/Music/Artists/The Offspring/Rise and Fall Rage and Grace/The Offspring - Trust In You.mp3
+C:/Users/Rik/Music/Artists/The Offspring/Rise and Fall Rage and Grace/The Offspring - You're Gonna Go Far, Kid.mp3
+C:/Users/Rik/Music/Artists/Nickelback/Here and Now/Nickelback - Bottoms Up.mp3
+C:/Users/Rik/Music/Artists/Nickelback/Here and Now/Nickelback - Don't Ever Let It End.mp3
+C:/Users/Rik/Music/Artists/Nickelback/Here and Now/Nickelback - Everything I Wanna Do.mp3
+C:/Users/Rik/Music/Artists/Nickelback/Here and Now/Nickelback - Gotta Get Me Some.mp3
+C:/Users/Rik/Music/Artists/Nickelback/Here and Now/Nickelback - Holding On to Heaven.mp3
+C:/Users/Rik/Music/Artists/Nickelback/Here and Now/Nickelback - Kiss It Goodbye.mp3
+C:/Users/Rik/Music/Artists/Nickelback/Here and Now/Nickelback - Lullaby.mp3
+C:/Users/Rik/Music/Artists/Nickelback/Here and Now/Nickelback - Midnight Queen.mp3
+C:/Users/Rik/Music/Artists/Nickelback/Here and Now/Nickelback - This Means War.mp3
+C:/Users/Rik/Music/Artists/Nickelback/Here and Now/Nickelback - Trying Not to Love You.mp3
+C:/Users/Rik/Music/Artists/Nickelback/Here and Now/Nickelback - When We Stand Together.mp3
+C:/Users/Rik/Music/Artists/The Vaccines/What Did You Expect From The Vaccines/The Vaccines - A Lack of Understanding.mp3
+C:/Users/Rik/Music/Artists/The Vaccines/What Did You Expect From The Vaccines/The Vaccines - All in White.mp3
+C:/Users/Rik/Music/Artists/The Vaccines/What Did You Expect From The Vaccines/The Vaccines - Blow It Up.mp3
+C:/Users/Rik/Music/Artists/The Vaccines/What Did You Expect From The Vaccines/The Vaccines - Family Friend.mp3
+C:/Users/Rik/Music/Artists/The Vaccines/What Did You Expect From The Vaccines/The Vaccines - If You Wanna.mp3
+C:/Users/Rik/Music/Artists/The Vaccines/What Did You Expect From The Vaccines/The Vaccines - N%C3%B8rgaard.mp3
+C:/Users/Rik/Music/Artists/The Vaccines/What Did You Expect From The Vaccines/The Vaccines - Post Break-Up Sex.mp3
+C:/Users/Rik/Music/Artists/The Vaccines/What Did You Expect From The Vaccines/The Vaccines - Under Your Thumb.mp3
+C:/Users/Rik/Music/Artists/The Vaccines/What Did You Expect From The Vaccines/The Vaccines - Westsuit.mp3
+C:/Users/Rik/Music/Artists/The Vaccines/What Did You Expect From The Vaccines/The Vaccines - Wolf Pack.mp3
+C:/Users/Rik/Music/Artists/The Vaccines/What Did You Expect From The Vaccines/The Vaccines - Wreckin' Bar.mp3
+C:/Users/Rik/Music/Artists/Daughtry/Leave This Town/Daughtry - Call Your Name.mp3
+C:/Users/Rik/Music/Artists/Daughtry/Leave This Town/Daughtry - Every Time You Turn Around.mp3
+C:/Users/Rik/Music/Artists/Daughtry/Leave This Town/Daughtry - Ghost Of Me.mp3
+C:/Users/Rik/Music/Artists/Daughtry/Leave This Town/Daughtry - Learn My Lesson.mp3
+C:/Users/Rik/Music/Artists/Daughtry/Leave This Town/Daughtry - Life After You.mp3
+C:/Users/Rik/Music/Artists/Daughtry/Leave This Town/Daughtry - No Surprise.mp3
+C:/Users/Rik/Music/Artists/Daughtry/Leave This Town/Daughtry - Open Up Your Eyes.mp3
+C:/Users/Rik/Music/Artists/Daughtry/Leave This Town/Daughtry - September.mp3
+C:/Users/Rik/Music/Artists/Daughtry/Leave This Town/Daughtry - Supernatural.mp3
+C:/Users/Rik/Music/Artists/Daughtry/Leave This Town/Daughtry - Tennessee Line.mp3
+C:/Users/Rik/Music/Artists/Daughtry/Leave This Town/Daughtry - What I Meant To Say.mp3
+C:/Users/Rik/Music/Artists/Daughtry/Leave This Town/Daughtry - You Don't Belong.mp3
+C:/Users/Rik/Music/Artists/Moke/The Long & Dangerous Sea/Moke - Black And Blue.mp3
+C:/Users/Rik/Music/Artists/Moke/The Long & Dangerous Sea/Moke - Ghost.mp3
+C:/Users/Rik/Music/Artists/Moke/The Long & Dangerous Sea/Moke - Heaven.mp3
+C:/Users/Rik/Music/Artists/Moke/The Long & Dangerous Sea/Moke - Lament.mp3
+C:/Users/Rik/Music/Artists/Moke/The Long & Dangerous Sea/Moke - Love My Life.mp3
+C:/Users/Rik/Music/Artists/Moke/The Long & Dangerous Sea/Moke - Nobody's Listening.mp3
+C:/Users/Rik/Music/Artists/Moke/The Long & Dangerous Sea/Moke - Switch.mp3
+C:/Users/Rik/Music/Artists/Moke/The Long & Dangerous Sea/Moke - Terrible End.mp3
+C:/Users/Rik/Music/Artists/Moke/The Long & Dangerous Sea/Moke - The Long & Dangerous Sea.mp3
+C:/Users/Rik/Music/Artists/Moke/The Long & Dangerous Sea/Moke - Windows Of Hope.mp3
+C:/Users/Rik/Music/Artists/Placebo/Battle for the Sun/Placebo - Ashtray Heart.mp3
+C:/Users/Rik/Music/Artists/Placebo/Battle for the Sun/Placebo - Battle for the Sun.mp3
+C:/Users/Rik/Music/Artists/Placebo/Battle for the Sun/Placebo - Breathe Underwater.mp3
+C:/Users/Rik/Music/Artists/Placebo/Battle for the Sun/Placebo - Bright Lights.mp3
+C:/Users/Rik/Music/Artists/Placebo/Battle for the Sun/Placebo - Come Undone.mp3
+C:/Users/Rik/Music/Artists/Placebo/Battle for the Sun/Placebo - Devil in the Details.mp3
+C:/Users/Rik/Music/Artists/Placebo/Battle for the Sun/Placebo - For What It's Worth.mp3
+C:/Users/Rik/Music/Artists/Placebo/Battle for the Sun/Placebo - Happy You're Gone.mp3
+C:/Users/Rik/Music/Artists/Placebo/Battle for the Sun/Placebo - Julien.mp3
+C:/Users/Rik/Music/Artists/Placebo/Battle for the Sun/Placebo - Kings of Medicine.mp3
+C:/Users/Rik/Music/Artists/Placebo/Battle for the Sun/Placebo - Kitty Litter.mp3
+C:/Users/Rik/Music/Artists/Placebo/Battle for the Sun/Placebo - Speak in Tongues.mp3
+C:/Users/Rik/Music/Artists/Placebo/Battle for the Sun/Placebo - The Never-Ending Why.mp3
+C:/Users/Rik/Music/Artists/Keane/Night Train/Keane - Back In Time.mp3
+C:/Users/Rik/Music/Artists/Keane/Night Train/Keane - Clear Skies.mp3
+C:/Users/Rik/Music/Artists/Keane/Night Train/Keane - House Lights.mp3
+C:/Users/Rik/Music/Artists/Keane/Night Train/Keane - Ishin Denshin (You've Got To Help Yourself).mp3
+C:/Users/Rik/Music/Artists/Keane/Night Train/Keane - Looking Back.mp3
+C:/Users/Rik/Music/Artists/Keane/Night Train/Keane - My Shadow.mp3
+C:/Users/Rik/Music/Artists/Keane/Night Train/Keane - Stop For a Minute.mp3
+C:/Users/Rik/Music/Artists/Keane/Night Train/Keane - Your Love.mp3
+C:/Users/Rik/Music/Artists/Keane/Under The Iron Sea/Keane - A Bad Dream.mp3
+C:/Users/Rik/Music/Artists/Keane/Under The Iron Sea/Keane - Atlantic.mp3
+C:/Users/Rik/Music/Artists/Keane/Under The Iron Sea/Keane - Broken Toy.mp3
+C:/Users/Rik/Music/Artists/Keane/Under The Iron Sea/Keane - Crystal Ball.mp3
+C:/Users/Rik/Music/Artists/Keane/Under The Iron Sea/Keane - Hamburg Song.mp3
+C:/Users/Rik/Music/Artists/Keane/Under The Iron Sea/Keane - Is It Any Wonder.mp3
+C:/Users/Rik/Music/Artists/Keane/Under The Iron Sea/Keane - Leaving So Soon.mp3
+C:/Users/Rik/Music/Artists/Keane/Under The Iron Sea/Keane - Let It Slide .mp3
+C:/Users/Rik/Music/Artists/Keane/Under The Iron Sea/Keane - Nothing In My Way.mp3
+C:/Users/Rik/Music/Artists/Keane/Under The Iron Sea/Keane - Put It Behind You.mp3
+C:/Users/Rik/Music/Artists/Keane/Under The Iron Sea/Keane - The Frog Prince.mp3
+C:/Users/Rik/Music/Artists/Keane/Under The Iron Sea/Keane - The Iron Sea.mp3
+C:/Users/Rik/Music/Artists/Keane/Under The Iron Sea/Keane - Try Again.mp3
+C:/Users/Rik/Music/Artists/Hey Monday/Hold On Tight/Hey Monday - 6 Months.mp3
+C:/Users/Rik/Music/Artists/Hey Monday/Hold On Tight/Hey Monday - Arizona.mp3
+C:/Users/Rik/Music/Artists/Hey Monday/Hold On Tight/Hey Monday - Candles.mp3
+C:/Users/Rik/Music/Artists/Hey Monday/Hold On Tight/Hey Monday - Homecoming.mp3
+C:/Users/Rik/Music/Artists/Hey Monday/Hold On Tight/Hey Monday - How You Love Me Now.mp3
+C:/Users/Rik/Music/Artists/Hey Monday/Hold On Tight/Hey Monday - Hurricane Streets.mp3
+C:/Users/Rik/Music/Artists/Hey Monday/Hold On Tight/Hey Monday - Josey.mp3
+C:/Users/Rik/Music/Artists/Hey Monday/Hold On Tight/Hey Monday - Obvious.mp3
+C:/Users/Rik/Music/Artists/Hey Monday/Hold On Tight/Hey Monday - Run, Don't Walk.mp3
+C:/Users/Rik/Music/Artists/Hey Monday/Hold On Tight/Hey Monday - Set Off.mp3
+C:/Users/Rik/Music/Artists/Hey Monday/Hold On Tight/Hey Monday - Should've Tried Harder.mp3
+C:/Users/Rik/Music/Artists/Mae/The Everglow/Mae - Anything.mp3
+C:/Users/Rik/Music/Artists/Mae/The Everglow/Mae - Breakdown.mp3
+C:/Users/Rik/Music/Artists/Mae/The Everglow/Mae - Cover Me.mp3
+C:/Users/Rik/Music/Artists/Mae/The Everglow/Mae - Epilogue.mp3
+C:/Users/Rik/Music/Artists/Mae/The Everglow/Mae - Mistakes we Knew we Were Making.mp3
+C:/Users/Rik/Music/Artists/Mae/The Everglow/Mae - Painless.mp3
+C:/Users/Rik/Music/Artists/Mae/The Everglow/Mae - Prologue.mp3
+C:/Users/Rik/Music/Artists/Mae/The Everglow/Mae - Ready and Waiting to Fall.mp3
+C:/Users/Rik/Music/Artists/Mae/The Everglow/Mae - Someone Else's Arms.mp3
+C:/Users/Rik/Music/Artists/Mae/The Everglow/Mae - Suspension.mp3
+C:/Users/Rik/Music/Artists/Mae/The Everglow/Mae - The Everglow.mp3
+C:/Users/Rik/Music/Artists/Mae/The Everglow/Mae - The Ocean.mp3
+C:/Users/Rik/Music/Artists/Mae/The Everglow/Mae - The Sun and the Moon.mp3
+C:/Users/Rik/Music/Artists/Mae/The Everglow/Mae - This is the Countdown.mp3
+C:/Users/Rik/Music/Artists/Mae/The Everglow/Mae - We're So Far Away.mp3
+C:/Users/Rik/Music/Artists/Saves the Day/Saves the Day - All I'm Losing Is Me.mp3
+C:/Users/Rik/Music/Artists/Saves the Day/Saves the Day - At Your Funeral.mp3
+C:/Users/Rik/Music/Artists/Saves the Day/Saves the Day - Cars And Calories.mp3
+C:/Users/Rik/Music/Artists/Saves the Day/Saves the Day - Certain Tragedy.mp3
+C:/Users/Rik/Music/Artists/Saves the Day/Saves the Day - Firefly.mp3
+C:/Users/Rik/Music/Artists/Saves the Day/Saves the Day - Freakish.mp3
+C:/Users/Rik/Music/Artists/Saves the Day/Saves the Day - Jukebox Breakdown.mp3
+C:/Users/Rik/Music/Artists/Saves the Day/Saves the Day - Nightingale.mp3
+C:/Users/Rik/Music/Artists/Saves the Day/Saves the Day - See You.mp3
+C:/Users/Rik/Music/Artists/Saves the Day/Saves the Day - This Is Not An Exit.mp3
+C:/Users/Rik/Music/Artists/Saves the Day/Saves the Day - Your Ghost Takes Flight.mp3
\ No newline at end of file
diff --git a/java/txt/options b/java/txt/options
new file mode 100644
index 0000000..4d95aae
--- /dev/null
+++ b/java/txt/options
@@ -0,0 +1,182 @@
+LAME 32bits version 3.98.4 (http://www.mp3dev.org/)
+
+usage: lame [options] [outfile]
+
+ and/or can be "-", which means stdin/stdout.
+
+RECOMMENDED:
+ lame -V2 input.wav output.mp3
+
+OPTIONS:
+ Input options:
+ --scale scale input (multiply PCM data) by
+ --scale-l scale channel 0 (left) input (multiply PCM data) by
+ --scale-r scale channel 1 (right) input (multiply PCM data) by
+ --mp1input input file is a MPEG Layer I file
+ --mp2input input file is a MPEG Layer II file
+ --mp3input input file is a MPEG Layer III file
+ --nogap <...>
+ gapless encoding for a set of contiguous files
+ --nogapout
+ output dir for gapless encoding (must precede --nogap)
+ --nogaptags allow the use of VBR tags in gapless encoding
+
+ Input options for RAW PCM:
+ -r input is raw pcm
+ -x force byte-swapping of input
+ -s sfreq sampling frequency of input file (kHz) - default 44.1 kHz
+ --bitwidth w input bit width is w (default 16)
+ --signed input is signed (default)
+ --unsigned input is unsigned
+ --little-endian input is little-endian (default)
+ --big-endian input is big-endian
+
+
+ Operational options:
+ -a downmix from stereo to mono file for mono encoding
+ -m (j)oint, (s)imple, (f)orce, (d)dual-mono, (m)ono
+ default is (j) or (s) depending on bitrate
+ joint = joins the best possible of MS and LR stereo
+ simple = force LR stereo on all frames
+ force = force MS stereo on all frames.
+ --preset type type must be "medium", "standard", "extreme", "insane",
+ or a value for an average desired bitrate and depending
+ on the value specified, appropriate quality settings will
+ be used.
+ "--preset help" gives more info on these
+ --comp choose bitrate to achive a compression ratio of
+ --replaygain-fast compute RG fast but slightly inaccurately (default)
+ --replaygain-accurate compute RG more accurately and find the peak sample
+ --noreplaygain disable ReplayGain analysis
+ --clipdetect enable --replaygain-accurate and print a message whether
+ clipping occurs and how far the waveform is from full scale
+ --flush flush output stream as soon as possible
+ --freeformat produce a free format bitstream
+ --decode input=mp3 file, output=wav
+ -t disable writing wav header when using --decode
+
+
+ Verbosity:
+ --disptime print progress report every arg seconds
+ -S don't print progress report, VBR histograms
+ --nohist disable VBR histogram display
+ --silent don't print anything on screen
+ --quiet don't print anything on screen
+ --brief print more useful information
+ --verbose print a lot of useful information
+
+ Noise shaping & psycho acoustic algorithms:
+ -q = 0...9. Default -q 5
+ -q 0: Highest quality, very slow
+ -q 9: Poor quality, but fast
+ -h Same as -q 2. Recommended.
+ -f Same as -q 7. Fast, ok quality
+
+
+ CBR (constant bitrate, the default) options:
+ -b set the bitrate in kbps, default 128 kbps
+ --cbr enforce use of constant bitrate
+
+ ABR options:
+ --abr specify average bitrate desired (instead of quality)
+
+ VBR options:
+ -V n quality setting for VBR. default n=4
+ 0=high quality,bigger files. 9=smaller files
+ -v the same as -V 4
+ --vbr-old use old variable bitrate (VBR) routine
+ --vbr-new use new variable bitrate (VBR) routine (default)
+ -b specify minimum allowed bitrate, default 32 kbps
+ -B specify maximum allowed bitrate, default 320 kbps
+ -F strictly enforce the -b option, for use with players that
+ do not support low bitrate mp3
+ -t disable writing LAME Tag
+ -T enable and force writing LAME Tag
+
+
+ PSY related:
+ --temporal-masking x x=0 disables, x=1 enables temporal masking effect
+ --nssafejoint M/S switching criterion
+ --nsmsfix M/S switching tuning [effective 0-3.5]
+ --interch x adjust inter-channel masking ratio
+ --ns-bass x adjust masking for sfbs 0 - 6 (long) 0 - 5 (short)
+ --ns-alto x adjust masking for sfbs 7 - 13 (long) 6 - 10 (short)
+ --ns-treble x adjust masking for sfbs 14 - 21 (long) 11 - 12 (short)
+ --ns-sfb21 x change ns-treble by x dB for sfb21
+
+
+ experimental switches:
+ -Y lets LAME ignore noise in sfb21, like in CBR
+
+
+ MP3 header/stream options:
+ -e de-emphasis n/5/c (obsolete)
+ -c mark as copyright
+ -o mark as non-original
+ -p error protection. adds 16 bit checksum to every frame
+ (the checksum is computed correctly)
+ --nores disable the bit reservoir
+ --strictly-enforce-ISO comply as much as possible to ISO MPEG spec
+
+ Filter options:
+ --lowpass frequency(kHz), lowpass filter cutoff above freq
+ --lowpass-width frequency(kHz) - default 15% of lowpass freq
+ --highpass frequency(kHz), highpass filter cutoff below freq
+ --highpass-width frequency(kHz) - default 15% of highpass freq
+ --resample sampling frequency of output file(kHz)- default=automatic
+
+
+ ID3 tag options:
+ --tt audio/song title (max 30 chars for version 1 tag)
+ --ta audio/song artist (max 30 chars for version 1 tag)
+ --tl audio/song album (max 30 chars for version 1 tag)
+ --ty audio/song year of issue (1 to 9999)
+ --tc user-defined text (max 30 chars for v1 tag, 28 for v1.1)
+ --tn