Last active
October 16, 2023 16:01
-
-
Save linnet8989/38b64748cfacdbbc2b5391c7863c6f44 to your computer and use it in GitHub Desktop.
Tricks of C++ and Windows API
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// EnumString - A utility to provide stringizing support for C++ enums | |
// Author: Francis Xavier Joseph Pulikotil | |
// Improved by: linnet8989 | |
// | |
// This code is free software: you can do whatever you want with it, | |
// although I would appreciate if you gave credit where it's due. | |
// | |
// This code is distributed in the hope that it will be useful, | |
// but WITHOUT ANY WARRANTY; without even the implied warranty of | |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
#ifndef ENUMSTRING_HEADER | |
#define ENUMSTRING_HEADER | |
/* Usage example | |
// EnumString - A utility to provide stringizing support for C++ enums | |
// Author: Francis Xavier Joseph Pulikotil | |
// | |
// This code is free software: you can do whatever you want with it, | |
// although I would appreciate if you gave credit where it's due. | |
// | |
// This code is distributed in the hope that it will be useful, | |
// but WITHOUT ANY WARRANTY; without even the implied warranty of | |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
#ifndef ENUMSTRING_HEADER | |
#define ENUMSTRING_HEADER | |
/* Usage example | |
// WeekEnd enumeration | |
#ifndef BEFORE_CPP11 | |
enum class WeekEnd | |
{ | |
//NotApplicable = 0, | |
Sunday = 1, | |
Saturday = 7 | |
}; | |
#else | |
namespace WeekEnd | |
{ | |
enum _WeekEnd | |
{ | |
//NotApplicable = 0, | |
Sunday = 1, | |
Saturday = 7 | |
}; | |
} | |
typedef WeekEnd::_WeekEnd WeekEnd | |
#endif // !BEFORE_CPP11 | |
// String support for WeekEnd | |
Begin_Enum_String( WeekEnd ) | |
{ | |
//Enum_String( NotApplicable ); | |
Enum_String( Sunday ); | |
Enum_String( Saturday ); | |
} | |
End_Enum_String; | |
// Convert from WeekEnd to string | |
#ifndef UNRESTRICTED_WITH_ENUMERATION_NAME | |
const std::string &str = EnumString<WeekEnd>::From( WeekEnd::Saturday ); | |
#else | |
const std::string &str = EnumString<WeekEnd>::From( Saturday ); | |
#endif // !UNRESTRICTED_WITH_ENUMERATION_NAME | |
// str should now be "Saturday" | |
// Convert from string to WeekEnd | |
WeekEnd w = EnumString<WeekEnd>::To( "Sunday" ); | |
// w should now be Sunday | |
*/ | |
#include <string> | |
#include <map> | |
#include <cassert> | |
#include "MacroHelper.h" // Optional | |
// Deprecated, unrestricted code wasn't tested. | |
// #define UNRESTRICTED_WITH_ENUMERATION_NAME | |
// Helper macros | |
#ifndef UNRESTRICTED_WITH_ENUMERATION_NAME | |
#ifndef BEFORE_CPP11 // using _EnumerationName = EnumerationName; | |
#define Begin_Enum_String(EnumerationName) \ | |
template <> struct EnumString<EnumerationName> : \ | |
public EnumStringBase< EnumString<EnumerationName>, EnumerationName > \ | |
{ \ | |
using _EnumerationName = EnumerationName; \ | |
static void RegisterEnumerators() | |
#else // using namespace EnumerationName; | |
#define Begin_Enum_String(EnumerationName) \ | |
template <> struct EnumString<EnumerationName> : \ | |
public EnumStringBase< EnumString<EnumerationName>, EnumerationName > \ | |
{ \ | |
using namespace EnumerationName; \ | |
static void RegisterEnumerators() | |
#endif // !BEFORE_CPP11 | |
#else | |
#define Begin_Enum_String(EnumerationName) \ | |
template <> struct EnumString<EnumerationName> : \ | |
public EnumStringBase< EnumString<EnumerationName>, EnumerationName > \ | |
{ \ | |
static void RegisterEnumerators() | |
#endif // !UNRESTRICTED_WITH_ENUMERATION_NAME | |
// { | |
#if !defined(BEFORE_CPP11) && !defined(UNRESTRICTED_WITH_ENUMERATION_NAME) | |
#define Enum_String(EnumeratorName) \ | |
RegisterEnumerator( _EnumerationName::EnumeratorName, #EnumeratorName ); | |
#else | |
#define Enum_String(EnumeratorName) \ | |
RegisterEnumerator( EnumeratorName, #EnumeratorName ); | |
#endif // !BEFORE_CPP11 && !UNRESTRICTED_WITH_ENUMERATION_NAME | |
// } | |
#define End_Enum_String \ | |
} | |
// The EnumString base class | |
template <class DerivedType, class EnumType> | |
class EnumStringBase | |
{ | |
// Types | |
protected: | |
typedef std::map<std::string, EnumType> AssocMap; | |
protected: | |
// Constructor / Destructor | |
explicit EnumStringBase(); | |
~EnumStringBase(); | |
private: | |
// Copy Constructor / Assignment Operator | |
EnumStringBase(const EnumStringBase &); | |
const EnumStringBase &operator =(const EnumStringBase &); | |
// Functions | |
private: | |
static AssocMap &GetMap(); | |
protected: | |
// Use this helper function to register each enumerator | |
// and its string representation. | |
static void RegisterEnumerator(const EnumType e, const std::string &eStr); | |
public: | |
// Converts from an enumerator to a string. | |
// Returns an empty string if the enumerator was not registered. | |
static const std::string &From(const EnumType e); | |
// Converts from a string to an enumerator. | |
// Returns the associated enumerator if the conversion is successful; EnumType::NotApplicable otherwise. | |
static EnumType To(const std::string str); | |
}; | |
// The EnumString class | |
// Note: Specialize this class for each enumeration, and implement | |
// the RegisterEnumerators() function. | |
template <class EnumType> | |
struct EnumString : public EnumStringBase< EnumString<EnumType>, EnumType > | |
{ | |
static void RegisterEnumerators(); | |
}; | |
// Function definitions | |
template <class D, class E> | |
typename EnumStringBase<D,E>::AssocMap &EnumStringBase<D,E>::GetMap() | |
{ | |
// A static map of associations from strings to enumerators | |
static AssocMap assocMap; | |
static bool bFirstAccess = true; | |
// If this is the first time we're accessing the map, then populate it. | |
if( bFirstAccess ) | |
{ | |
bFirstAccess = false; | |
D::RegisterEnumerators(); | |
assert( !assocMap.empty() ); | |
} | |
return assocMap; | |
} | |
template <class D, class E> | |
void EnumStringBase<D,E>::RegisterEnumerator(const E e, const std::string &eStr) | |
{ | |
const bool bRegistered = GetMap().insert( typename AssocMap::value_type( eStr, e ) ).second; | |
assert( bRegistered ); | |
(void)sizeof( bRegistered ); // This is to avoid the pesky 'unused variable' warning in Release Builds. | |
} | |
template <class D, class E> | |
const std::string &EnumStringBase<D,E>::From(const E e) | |
{ | |
for(;;) // Code block | |
{ | |
// Search for the enumerator in our map | |
typename AssocMap::const_iterator i; | |
for(i = GetMap().begin(); i != GetMap().end(); ++i) | |
if( (*i).second == e ) | |
break; | |
// If we didn't find it, we can't do this conversion | |
if( i == GetMap().end() ) | |
break; | |
// Keep searching and see if we find another one with the same value | |
typename AssocMap::const_iterator j( i ); | |
for(++j; j != GetMap().end(); ++j) | |
if( (*j).second == e ) | |
break; | |
// If we found another one with the same value, we can't do this conversion | |
if( j != GetMap().end() ) | |
break; | |
// We found exactly one string which matches the required enumerator | |
return (*i).first; | |
} | |
// We couldn't do this conversion; return an empty string. | |
static const std::string dummy; | |
return dummy; | |
} | |
template <class D, class E> | |
E EnumStringBase<D,E>::To(const std::string str) | |
{ | |
// Search for the string in our map. | |
const typename AssocMap::const_iterator itr( GetMap().find( str ) ); | |
// If we have it, then return the associated enumerator. | |
if( itr != GetMap().end() ) | |
{ | |
return (*itr).second; | |
} | |
// We don't have it; the conversion failed. | |
#if !defined(BEFORE_CPP11) && !defined(UNRESTRICTED_WITH_ENUMERATION_NAME) | |
return E::NotApplicable; | |
#else | |
return NotApplicable; | |
#endif // !BEFORE_CPP11 && !UNRESTRICTED_WITH_ENUMERATION_NAME | |
//return GetMap()[str]; | |
} | |
#endif | |
// WeekEnd enumeration | |
#ifndef BEFORE_CPP11 | |
enum class WeekEnd | |
{ | |
//NotApplicable = 0, | |
Sunday = 1, | |
Saturday = 7 | |
}; | |
#else | |
namespace WeekEnd | |
{ | |
enum _WeekEnd | |
{ | |
//NotApplicable = 0, | |
Sunday = 1, | |
Saturday = 7 | |
}; | |
} | |
typedef WeekEnd::_WeekEnd WeekEnd | |
#endif // !BEFORE_CPP11 | |
// String support for WeekEnd | |
Begin_Enum_String( WeekEnd ) | |
{ | |
//Enum_String( NotApplicable ); | |
Enum_String( Sunday ); | |
Enum_String( Saturday ); | |
} | |
End_Enum_String; | |
// Convert from WeekEnd to string | |
#ifndef UNRESTRICTED_WITH_ENUMERATION_NAME | |
const std::string &str = EnumString<WeekEnd>::From( WeekEnd::Saturday ); | |
#else | |
const std::string &str = EnumString<WeekEnd>::From( Saturday ); | |
#endif // !UNRESTRICTED_WITH_ENUMERATION_NAME | |
// str should now be "Saturday" | |
// Convert from string to WeekEnd | |
WeekEnd w = EnumString<WeekEnd>::To( "Sunday" ); | |
// w should now be Sunday | |
*/ | |
#include <string> | |
#include <map> | |
#include <cassert> | |
// Deprecated, unrestricted code wasn't tested. | |
// #define UNRESTRICTED_WITH_ENUMERATION_NAME | |
// Helper macros | |
#ifndef UNRESTRICTED_WITH_ENUMERATION_NAME | |
#ifndef BEFORE_CPP11 // using _EnumerationName = EnumerationName; | |
#define Begin_Enum_String(EnumerationName) \ | |
template <> struct EnumString<EnumerationName> : \ | |
public EnumStringBase< EnumString<EnumerationName>, EnumerationName > \ | |
{ \ | |
using _EnumerationName = EnumerationName; \ | |
static void RegisterEnumerators() | |
#else // using namespace EnumerationName; | |
#define Begin_Enum_String(EnumerationName) \ | |
template <> struct EnumString<EnumerationName> : \ | |
public EnumStringBase< EnumString<EnumerationName>, EnumerationName > \ | |
{ \ | |
using namespace EnumerationName; \ | |
static void RegisterEnumerators() | |
#endif // !BEFORE_CPP11 | |
#else | |
#define Begin_Enum_String(EnumerationName) \ | |
template <> struct EnumString<EnumerationName> : \ | |
public EnumStringBase< EnumString<EnumerationName>, EnumerationName > \ | |
{ \ | |
static void RegisterEnumerators() | |
#endif // !UNRESTRICTED_WITH_ENUMERATION_NAME | |
// { | |
#if !defined(BEFORE_CPP11) && !defined(UNRESTRICTED_WITH_ENUMERATION_NAME) | |
#define Enum_String(EnumeratorName) \ | |
RegisterEnumerator( _EnumerationName::EnumeratorName, #EnumeratorName ); | |
#else | |
#define Enum_String(EnumeratorName) \ | |
RegisterEnumerator( EnumeratorName, #EnumeratorName ); | |
#endif // !BEFORE_CPP11 && !UNRESTRICTED_WITH_ENUMERATION_NAME | |
// } | |
#define End_Enum_String \ | |
} | |
// The EnumString base class | |
template <class DerivedType, class EnumType> | |
class EnumStringBase | |
{ | |
// Types | |
protected: | |
typedef std::map<std::string, EnumType> AssocMap; | |
protected: | |
// Constructor / Destructor | |
explicit EnumStringBase(); | |
~EnumStringBase(); | |
private: | |
// Copy Constructor / Assignment Operator | |
EnumStringBase(const EnumStringBase &); | |
const EnumStringBase &operator =(const EnumStringBase &); | |
// Functions | |
private: | |
static AssocMap &GetMap(); | |
protected: | |
// Use this helper function to register each enumerator | |
// and its string representation. | |
static void RegisterEnumerator(const EnumType e, const std::string &eStr); | |
public: | |
// Converts from an enumerator to a string. | |
// Returns an empty string if the enumerator was not registered. | |
static const std::string &From(const EnumType e); | |
// Converts from a string to an enumerator. | |
// Returns the associated enumerator if the conversion is successful; EnumType::NotApplicable otherwise. | |
static EnumType To(const std::string str); | |
}; | |
// The EnumString class | |
// Note: Specialize this class for each enumeration, and implement | |
// the RegisterEnumerators() function. | |
template <class EnumType> | |
struct EnumString : public EnumStringBase< EnumString<EnumType>, EnumType > | |
{ | |
static void RegisterEnumerators(); | |
}; | |
// Function definitions | |
template <class D, class E> | |
typename EnumStringBase<D,E>::AssocMap &EnumStringBase<D,E>::GetMap() | |
{ | |
// A static map of associations from strings to enumerators | |
static AssocMap assocMap; | |
static bool bFirstAccess = true; | |
// If this is the first time we're accessing the map, then populate it. | |
if( bFirstAccess ) | |
{ | |
bFirstAccess = false; | |
D::RegisterEnumerators(); | |
assert( !assocMap.empty() ); | |
} | |
return assocMap; | |
} | |
template <class D, class E> | |
void EnumStringBase<D,E>::RegisterEnumerator(const E e, const std::string &eStr) | |
{ | |
const bool bRegistered = GetMap().insert( typename AssocMap::value_type( eStr, e ) ).second; | |
assert( bRegistered ); | |
(void)sizeof( bRegistered ); // This is to avoid the pesky 'unused variable' warning in Release Builds. | |
} | |
template <class D, class E> | |
const std::string &EnumStringBase<D,E>::From(const E e) | |
{ | |
for(;;) // Code block | |
{ | |
// Search for the enumerator in our map | |
typename AssocMap::const_iterator i; | |
for(i = GetMap().begin(); i != GetMap().end(); ++i) | |
if( (*i).second == e ) | |
break; | |
// If we didn't find it, we can't do this conversion | |
if( i == GetMap().end() ) | |
break; | |
// Keep searching and see if we find another one with the same value | |
typename AssocMap::const_iterator j( i ); | |
for(++j; j != GetMap().end(); ++j) | |
if( (*j).second == e ) | |
break; | |
// If we found another one with the same value, we can't do this conversion | |
if( j != GetMap().end() ) | |
break; | |
// We found exactly one string which matches the required enumerator | |
return (*i).first; | |
} | |
// We couldn't do this conversion; return an empty string. | |
static const std::string dummy; | |
return dummy; | |
} | |
template <class D, class E> | |
E EnumStringBase<D,E>::To(const std::string str) | |
{ | |
//// Search for the string in our map. | |
//const typename AssocMap::const_iterator itr( GetMap().find( str ) ); | |
//// If we have it, then return the associated enumerator. | |
//if( itr != GetMap().end() ) | |
//{ | |
// return (*itr).second; | |
//} | |
//// We don't have it; the conversion failed. | |
#if !defined(BEFORE_CPP11) && !defined(UNRESTRICTED_WITH_ENUMERATION_NAME) | |
//return E::NotApplicable; | |
#else | |
//return NotApplicable; | |
#endif // !BEFORE_CPP11 && !UNRESTRICTED_WITH_ENUMERATION_NAME | |
return GetMap()[str]; | |
} | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <stdio.h> | |
#ifdef _UNICODE | |
#define strlenof(a) wcslen(a) | |
#define strsizeof(a) (wcslen(a) + 1) | |
#else | |
#define strlenof(a) strlen(a) | |
#define strsizeof(a) (strlen(a) + 1) | |
#endif // _UNICODE | |
#define arrsizeof(a) (sizeof(a) / sizeof(a[0]))#pragma once | |
#include <stdio.h> | |
#include <stddef.h> | |
#if (defined(__cplusplus) && __cplusplus >= 201103L) || (defined(_MSC_VER) && _MSC_VER >= 1800) | |
#define CPP11_AND_AFTER | |
#else | |
#define BEFORE_CPP11 | |
#endif | |
#ifdef _UNICODE | |
#define strlenof(a) wcslen(a) | |
#define strsizeof(a) (wcslen(a) + 1) | |
#else | |
#define strlenof(a) strlen(a) | |
#define strsizeof(a) (strlen(a) + 1) | |
#endif // _UNICODE | |
#define arrsizeof(a) (sizeof(a) / sizeof(*a)) | |
#define arrlenof(a) (arrsizeof(a) - 1) | |
#define SET_THIS(x) this->x = x; | |
#define RESET_THIS(x) this->x = obj.x; | |
#define PTR_ADD(p1, p2) ((uintptr_t)(p1) + (uintptr_t)(p2)) | |
#define PTR_SUB(p1, p2) ((ptrdiff_t)((uintptr_t)(p1) - (uintptr_t)(p2))) | |
#define ADDR_ADD_OFFSET(Address, Offset) ((ULONG_PTR)(Address) + (ULONG_PTR)(Offset)) | |
#define ADDR_SUB_OFFSET(Address, Offset) ((ULONG_PTR)(Address) - (ULONG_PTR)(Offset)) | |
#define ALIGN_UP_BY(Address, Align) (((ULONG_PTR)(Address) + (Align) - 1) & ~((Align) - 1)) | |
#define ALIGN_UP(Address, Type) ALIGN_UP_BY(Address, sizeof(Type)) | |
#define PTR_MOVE_OF(Pointer, Offset, Type) {Pointer = ((Type)ADDR_ADD_OFFSET(Pointer, Offset));} | |
#ifdef CPP11_AND_AFTER | |
#define PTR_ADD_OFFSET(Pointer, Offset) (decltype(Pointer)ADDR_ADD_OFFSET(Pointer, Offset)) | |
#define PTR_SUB_OFFSET(Pointer, Offset) (decltype(Pointer)ADDR_SUB_OFFSET(Pointer, Offset)) | |
#define ALIGN_UP_POINTER_BY(Pointer, Align) (decltype(Pointer)ALIGN_UP_BY(Pointer, Align)) | |
#define ALIGN_UP_POINTER(Pointer, Type) (decltype(Pointer)ALIGN_UP(Pointer, Type)) | |
#define PTR_MOVE(Pointer, Offset) PTR_MOVE_OF(Pointer, Offset, decltype(Pointer)) | |
#else | |
#define PTR_ADD_OFFSET(Pointer, Offset) ((PVOID)ADDR_ADD_OFFSET(Pointer, Offset)) | |
#define PTR_SUB_OFFSET(Pointer, Offset) ((PVOID)ADDR_SUB_OFFSET(Pointer, Offset)) | |
#define ALIGN_UP_POINTER_BY(Pointer, Align) ((PVOID)ALIGN_UP_BY(Pointer, Align)) | |
#define ALIGN_UP_POINTER(Pointer, Type) ((PVOID)ALIGN_UP(Pointer, Type)) | |
#define PTR_MOVE(Pointer, Offset) PTR_MOVE_OF(Pointer, Offset, PVOID) | |
#endif | |
#define MAX(a, b) (a < b ? b : a) | |
#define MIN(a, b) (a < b ? a : b) | |
#define CEIL_DIVIDE(dividend, divisor) (dividend % divisor == 0 ? dividend / divisor : dividend / divisor + 1) | |
#define arrlenof(a) (arrsizeof(a) - 1) | |
#define SET_THIS(x) this->x = x; | |
#define TEST_POINTER(type, addr, offset) ((type)((int)addr + offset)) | |
#define MOVE_POINTER(type, addr, offset) addr = (type)((int)addr + offset); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <string.h> | |
#include <string> | |
#include <vector> | |
#include <sstream> | |
int ReadLineA(char szBuf[], const int size, FILE * stream = stdin) | |
{ | |
int count = 0, ch = 0;#pragma once | |
#include <string.h> | |
#include <string> | |
#include <vector> | |
#include <sstream> | |
int ReadLineA(char szBuf[], const int size, FILE * stream = stdin) | |
{ | |
int count = 0, ch = 0; | |
for (; count + 1 < size && (ch = getc(stream)) != '\n'; count++) | |
{ | |
if (ch == EOF) return EOF; | |
szBuf[count] = ch; | |
} | |
if (count + 1 >= size && size >= 0 && stream == stdin) | |
{ | |
while ((ch = getchar()) != '\n' && ch != EOF); | |
} | |
return count; | |
} | |
#define ReadLine ReadLineA | |
namespace std | |
{ | |
vector<string> split_whitespace(string str) | |
{ | |
vector<string> result; | |
istringstream ss(str); | |
while (ss >> str) | |
{ | |
result.push_back(str); | |
} | |
return result; | |
} | |
vector<string> split(string str, string pattern, size_t maxsplits = -1, bool includeEmpty = false) | |
{ | |
vector<string> result; | |
string::size_type pos; | |
str += pattern;//��չ�ַ����Է������ | |
int size = str.size(); | |
int patternLength = pattern.size() - 1; | |
for (int i = 0; i < size; i++) | |
{ | |
pos = str.find(pattern, i); | |
if (pos < size) | |
{ | |
string s = str.substr(i, pos - i); | |
if (!s.empty() || includeEmpty) | |
{ | |
if (result.size() >= maxsplits) | |
{ | |
result.push_back(str.substr(i)); | |
return result; | |
} | |
result.push_back(s); | |
} | |
i = pos + patternLength; | |
} | |
} | |
return result; | |
} | |
string trim(const string str) | |
{ | |
string::size_type pos = str.find_first_not_of(' '); | |
if (pos == string::npos) | |
{ | |
return str; | |
} | |
string::size_type pos2 = str.find_last_not_of(' '); | |
if (pos2 != string::npos) | |
{ | |
return str.substr(pos, pos2 - pos + 1); | |
} | |
return str.substr(pos); | |
} | |
} | |
char *stptok( | |
const char *s,/* string to parse */ | |
char *tok, /* buffer that receives the "token" that gets scanned */ | |
size_t toklen,/* length of the buffer */ | |
const char *brk /* string of break characters that will stop the scan */) | |
{ | |
char *lim; /* limit of token */ | |
const char *b; /* current break character */ | |
/* check for invalid pointers */ | |
if (!s || !tok || !brk) | |
return NULL; | |
/* check for empty string */ | |
if (!*s) | |
return NULL; | |
lim = tok + toklen - 1; | |
while (*s && tok < lim) | |
{ | |
for (b = brk; *b; b++) | |
{ | |
if (*s == *b) | |
{ | |
*tok = 0; | |
for (++s, b = brk; *s && *b; ++b) | |
{ | |
if (*s == *b) | |
{ | |
++s; | |
b = brk; | |
} | |
} | |
if (!*s) | |
return NULL; | |
return (char *)s; | |
} | |
} | |
*tok++ = *s++; | |
} | |
*tok = 0; | |
if (!*s) | |
return NULL; | |
return (char *)s; | |
} | |
for (; count + 1 < size && (ch = getc(stream)) != '\n'; count++) | |
{ | |
if (ch == EOF) return EOF; | |
szBuf[count] = ch; | |
} | |
if (count + 1 >= size && size >= 0 && stream == stdin) | |
{ | |
while ((ch = getchar()) != '\n' && ch != EOF); | |
} | |
return count; | |
} | |
#define ReadLine ReadLineA | |
namespace std | |
{ | |
vector<string> split_whitespace(string str) | |
{ | |
vector<string> result; | |
istringstream ss(str); | |
while (ss >> str) | |
{ | |
result.push_back(str); | |
} | |
return result; | |
} | |
vector<string> split(string str, string pattern, size_t maxsplits = -1, bool includeEmpty = false) | |
{ | |
vector<string> result; | |
string::size_type pos; | |
str += pattern;//扩展字符串以方便操作 | |
int size = str.size(); | |
int patternLength = pattern.size() - 1; | |
for (int i = 0; i < size; i++) | |
{ | |
pos = str.find(pattern, i); | |
if (pos < size) | |
{ | |
string s = str.substr(i, pos - i); | |
if (!s.empty() || includeEmpty) | |
{ | |
if (result.size() >= maxsplits) | |
{ | |
result.push_back(str.substr(i)); | |
return result; | |
} | |
result.push_back(s); | |
} | |
i = pos + patternLength; | |
} | |
} | |
return result; | |
} | |
string trim(const string str) | |
{ | |
string::size_type pos = str.find_first_not_of(' '); | |
if (pos == string::npos) | |
{ | |
return str; | |
} | |
string::size_type pos2 = str.find_last_not_of(' '); | |
if (pos2 != string::npos) | |
{ | |
return str.substr(pos, pos2 - pos + 1); | |
} | |
return str.substr(pos); | |
} | |
} | |
char *stptok( | |
const char *s,/* string to parse */ | |
char *tok, /* buffer that receives the "token" that gets scanned */ | |
size_t toklen,/* length of the buffer */ | |
const char *brk /* string of break characters that will stop the scan */) | |
{ | |
char *lim; /* limit of token */ | |
const char *b; /* current break character */ | |
/* check for invalid pointers */ | |
if (!s || !tok || !brk) | |
return NULL; | |
/* check for empty string */ | |
if (!*s) | |
return NULL; | |
lim = tok + toklen - 1; | |
while (*s && tok < lim) | |
{ | |
for (b = brk; *b; b++) | |
{ | |
if (*s == *b) | |
{ | |
*tok = 0; | |
for (++s, b = brk; *s && *b; ++b) | |
{ | |
if (*s == *b) | |
{ | |
++s; | |
b = brk; | |
} | |
} | |
if (!*s) | |
return NULL; | |
return (char *)s; | |
} | |
} | |
*tok++ = *s++; | |
} | |
*tok = 0; | |
if (!*s) | |
return NULL; | |
return (char *)s; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "windows.h" | |
BOOL ReadProcessMemoryEx( | |
HANDLE hProcess, | |
LPCVOID lpBaseAddress, | |
LPVOID lpBuffer, | |
SIZE_T nSize, | |
SIZE_T * lpNumberOfBytesRead) | |
{ | |
// 考虑跨页读问题, 要读多次. | |
// e.g. 跨多页的问题 | |
// e.g. 从0x00401234 读 0x12345个字符到缓冲区 | |
BOOL bRc = FALSE; | |
DWORD dwPos = 0; | |
DWORD dwRd = 0; | |
DWORD dwRdBack = 0; | |
const DWORD dwPageCb = 0x1000; ///< 一页内存的size | |
DWORD dwRemainder = 0; | |
if (NULL != lpNumberOfBytesRead) | |
{ | |
*lpNumberOfBytesRead = 0; | |
} | |
// 读第一部分, 不对齐页的部分, 比一页小, 只读一次 | |
dwRemainder = dwPageCb - ((DWORD)lpBaseAddress % dwPageCb); | |
if (nSize <= dwRemainder) | |
{ | |
// 在页中间读的, 读的数据长度不到页尾, 一次读完返回 | |
bRc = ReadProcessMemory(#pragma once | |
#include "windows.h" | |
#include <Psapi.h> | |
BOOL ReadProcessMemoryEx( | |
HANDLE hProcess, | |
LPCVOID lpBaseAddress, | |
LPVOID lpBuffer, | |
SIZE_T nSize, | |
SIZE_T * lpNumberOfBytesRead) | |
{ | |
// ���ǿ�ҳ������, Ҫ�����. | |
// e.g. ���ҳ������ | |
// e.g. ��0x00401234 �� 0x12345���ַ��������� | |
BOOL bRc = FALSE; | |
DWORD dwPos = 0; | |
DWORD dwRd = 0; | |
DWORD dwRdBack = 0; | |
const DWORD dwPageCb = 0x1000; ///< һҳ�ڴ��size | |
DWORD dwRemainder = 0; | |
if (NULL != lpNumberOfBytesRead) | |
{ | |
*lpNumberOfBytesRead = 0; | |
} | |
// ����һ����, ������ҳ�IJ���, ��һҳС, ֻ��һ�� | |
dwRemainder = dwPageCb - ((DWORD)lpBaseAddress % dwPageCb); | |
if (nSize <= dwRemainder) | |
{ | |
// ��ҳ�м����, �������ݳ��Ȳ���ҳβ, һ�ζ��귵�� | |
bRc = ReadProcessMemory( | |
hProcess, | |
(void*)((DWORD)lpBaseAddress + dwPos), | |
(void*)((DWORD)lpBuffer + dwPos), | |
nSize, | |
&dwRdBack); | |
if (NULL != lpNumberOfBytesRead) | |
{ | |
*lpNumberOfBytesRead += dwRdBack; | |
} | |
if ((!bRc) || (dwRdBack != nSize)) | |
{ | |
return FALSE; | |
} | |
return bRc; | |
} | |
// Ҫ�������ݳ���ҳ�߽�� | |
if (dwRemainder > 0) | |
{ | |
nSize -= dwRemainder; | |
bRc = ReadProcessMemory( | |
hProcess, | |
(void*)((DWORD)lpBaseAddress + dwPos), | |
(void*)((DWORD)lpBuffer + dwPos), | |
dwRemainder, | |
&dwRdBack); | |
if (NULL != lpNumberOfBytesRead) | |
{ | |
*lpNumberOfBytesRead += dwRdBack; | |
} | |
if ((!bRc) || (dwRdBack != dwRemainder)) | |
{ | |
return FALSE; | |
} | |
dwPos += dwRdBack; | |
} | |
// �ظ�����2����, ��ҳ�Ķ� | |
while (nSize >= dwPageCb) | |
{ | |
nSize -= dwPageCb; | |
bRc = ReadProcessMemory( | |
hProcess, | |
(void*)((DWORD)lpBaseAddress + dwPos), | |
(void*)((DWORD)lpBuffer + dwPos), | |
dwPageCb, | |
&dwRdBack); | |
if (NULL != lpNumberOfBytesRead) | |
{ | |
*lpNumberOfBytesRead += dwRdBack; | |
} | |
if ((!bRc) || (dwRdBack != dwPageCb)) | |
{ | |
return FALSE; | |
} | |
dwPos += dwRdBack; | |
} | |
// ��β�Ͳ���, ��һҳС, ֻ��һ�ξ��� | |
if (nSize > 0) | |
{ | |
bRc = ReadProcessMemory( | |
hProcess, | |
(void*)((DWORD)lpBaseAddress + dwPos), | |
(void*)((DWORD)lpBuffer + dwPos), | |
nSize, | |
&dwRdBack); | |
if (NULL != lpNumberOfBytesRead) | |
{ | |
*lpNumberOfBytesRead += dwRdBack; | |
} | |
if ((!bRc) || (dwRdBack != nSize)) | |
{ | |
return FALSE; | |
} | |
} | |
return TRUE; | |
} | |
#define BUFSIZE 512 | |
string GetFileNameFromHandle(HANDLE hFile) | |
{ | |
BOOL bSuccess = FALSE; | |
TCHAR pszFilename[MAX_PATH + 1]; | |
HANDLE hFileMap; | |
// Get the file size. | |
DWORD dwFileSizeHi = 0; | |
DWORD dwFileSizeLo = GetFileSize(hFile, &dwFileSizeHi); | |
if (dwFileSizeLo == 0 && dwFileSizeHi == 0) | |
{ | |
_tprintf(TEXT("Cannot map a file with a length of zero.\n")); | |
return ""; | |
} | |
// Create a file mapping object. | |
hFileMap = CreateFileMapping(hFile, | |
NULL, | |
PAGE_READONLY, | |
0, | |
1, | |
NULL); | |
if (hFileMap) | |
{ | |
// Create a file mapping to get the file name. | |
void* pMem = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 1); | |
if (pMem) | |
{ | |
if (GetMappedFileName(GetCurrentProcess(), | |
pMem, | |
pszFilename, | |
MAX_PATH)) | |
{ | |
// Translate path with device name to drive letters. | |
TCHAR szTemp[BUFSIZE]; | |
szTemp[0] = '\0'; | |
if (GetLogicalDriveStrings(BUFSIZE - 1, szTemp)) | |
{ | |
TCHAR szName[MAX_PATH]; | |
TCHAR szDrive[3] = TEXT(" :"); | |
BOOL bFound = FALSE; | |
TCHAR* p = szTemp; | |
do | |
{ | |
// Copy the drive letter to the template string | |
*szDrive = *p; | |
// Look up each device name | |
if (QueryDosDevice(szDrive, szName, MAX_PATH)) | |
{ | |
size_t uNameLen = _tcslen(szName); | |
if (uNameLen < MAX_PATH) | |
{ | |
bFound = _tcsnicmp(pszFilename, szName, uNameLen) == 0 | |
&& *(pszFilename + uNameLen) == _T('\\'); | |
if (bFound) | |
{ | |
// Reconstruct pszFilename using szTempFile | |
// Replace device path with DOS path | |
TCHAR szTempFile[MAX_PATH]; | |
StringCchPrintf(szTempFile, | |
MAX_PATH, | |
TEXT("%s%s"), | |
szDrive, | |
pszFilename + uNameLen); | |
StringCchCopyN(pszFilename, MAX_PATH + 1, szTempFile, _tcslen(szTempFile)); | |
} | |
} | |
} | |
// Go to the next NULL character. | |
while (*p++); | |
} while (!bFound && *p); // end of string | |
} | |
} | |
bSuccess = TRUE; | |
UnmapViewOfFile(pMem); | |
} | |
CloseHandle(hFileMap); | |
} | |
//_tprintf(TEXT("File name is %s\n"), pszFilename); | |
return(pszFilename); | |
} | |
hProcess, | |
(void*)((DWORD)lpBaseAddress + dwPos), | |
(void*)((DWORD)lpBuffer + dwPos), | |
nSize, | |
&dwRdBack); | |
if (NULL != lpNumberOfBytesRead) | |
{ | |
*lpNumberOfBytesRead += dwRdBack; | |
} | |
if ((!bRc) || (dwRdBack != nSize)) | |
{ | |
return FALSE; | |
} | |
return bRc; | |
} | |
// 要读的数据超过页边界的 | |
if (dwRemainder > 0) | |
{ | |
nSize -= dwRemainder; | |
bRc = ReadProcessMemory( | |
hProcess, | |
(void*)((DWORD)lpBaseAddress + dwPos), | |
(void*)((DWORD)lpBuffer + dwPos), | |
dwRemainder, | |
&dwRdBack); | |
if (NULL != lpNumberOfBytesRead) | |
{ | |
*lpNumberOfBytesRead += dwRdBack; | |
} | |
if ((!bRc) || (dwRdBack != dwRemainder)) | |
{ | |
return FALSE; | |
} | |
dwPos += dwRdBack; | |
} | |
// 重复读第2部分, 整页的读 | |
while (nSize >= dwPageCb) | |
{ | |
nSize -= dwPageCb; | |
bRc = ReadProcessMemory( | |
hProcess, | |
(void*)((DWORD)lpBaseAddress + dwPos), | |
(void*)((DWORD)lpBuffer + dwPos), | |
dwPageCb, | |
&dwRdBack); | |
if (NULL != lpNumberOfBytesRead) | |
{ | |
*lpNumberOfBytesRead += dwRdBack; | |
} | |
if ((!bRc) || (dwRdBack != dwPageCb)) | |
{ | |
return FALSE; | |
} | |
dwPos += dwRdBack; | |
} | |
// 读尾巴部分, 比一页小, 只读一次就够了 | |
if (nSize > 0) | |
{ | |
bRc = ReadProcessMemory( | |
hProcess, | |
(void*)((DWORD)lpBaseAddress + dwPos), | |
(void*)((DWORD)lpBuffer + dwPos), | |
nSize, | |
&dwRdBack); | |
if (NULL != lpNumberOfBytesRead) | |
{ | |
*lpNumberOfBytesRead += dwRdBack; | |
} | |
if ((!bRc) || (dwRdBack != nSize)) | |
{ | |
return FALSE; | |
} | |
} | |
return TRUE; | |
} |
@linnet8989 would you be okay if I create a proper GitHub repository for this code and then package it into Vcpkg? I believe it could be useful to spread this code among folks through Vcpkg :).
If you want to create the GitHub repository that fine with me as well!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@linnet8989 would you be okay if I create a proper GitHub repository for this code and then package it into Vcpkg? I believe it could be useful to spread this code among folks through Vcpkg :).
If you want to create the GitHub repository that fine with me as well!