#ifndef UTILITIES_HPP_INCLUDED #define UTILITIES_HPP_INCLUDED // // (c) 1999-2002 . Salnikov George Yuriy (GeorgeSalnikov@comcast.net). // // ///////////////////////////////////////////////////////////////////////////////////////// // // a couple of useful macros to stringisize source code line number and generate an unique // name in scope of the source code file per line, and a custom message for MS IDE to be // able find source line clicking on this message, use last one as // #pragma message(MESSAGE_ANCHOR "some message") // // lengthof returns a length of "some constant string" without trailing zero // #define __INT_AS_STRING__0(x) #x #define __INT_AS_STRING__(x) __INT_AS_STRING__0(x) #define __LINE__STRING__ __INT_AS_STRING__(__LINE__) #define __FILE__LINE__ __FILE__"("__LINE__STRING__") " #define MESSAGE_ANCHOR __FILE__"("__LINE__STRING__"): GYS -- " #define UNIQUE_VARIABLE uniqueNameInThisFile_##__LINE__ #define lengthof(x) ((sizeof(x)-1) / sizeof(char )) ///////////////////////////////////////////////////////////////////////////////////////// // // DLL or static library declaration specifications // #if !defined(GYS_SPEC) #if defined(_DLL) #define GYS_SPEC __declspec(dllimport) #else #define GYS_SPEC #endif #endif ///////////////////////////////////////////////////////////////////////////////////////// // // 4786: identifier was truncated to 'xxx' characters in the debug information // 4251: non dll-interface class used for dll-interface class // 4275: non - DLL-interface classkey 'identifier' used as base for DLL-interface classkey 'identifier' // #pragma warning (disable: 4786 4251 4275) ///////////////////////////////////////////////////////////////////////////////////////// // #include // Windows' COM stuf such as _bstr_t, _com_error and so on #include // ATL support //#include // ATL support //#include // ::CoInitializeEx ???? #include // Win32 SE exception hook #include // std::streams forward declarations #include // std::stringstream #include // std::string #include // std::list #include // std::vector #include // std::map #include // std::endl, std::ends, boolalpha and so on #include // std::find, and such #include // std::exception #include // std::unary_..binary.._function, greater, less and so on #include // system time time_t and clock_t #include // // C's ::toupper, ::tolower (ANSI, Win 95, Win NT) //#include // windows processes // // uncomment the following to test memory leaks with call of _CrtDumpMemoryLeaks(); // //#define _CRTDBG_MAP_ALLOC //#include //#include ///////////////////////////////////////////////////////////////////////////////////////// // // std::pair adapters: template struct select1st; // void do_something(string s); template struct select2nd; // typedef map dict; template struct do_nothing; // function object that does nothing //template struct select1st_reference; // dict d; //template struct select2nd_reference; // for_each(d.begin(), d.end(), // bind1st(do_something, select2nd::value_type())); //template // cast TStruct to TMember // class cast; // .. throw no exception but return 0 inline std::string& trim_left(std::string& s); // NOTE: they trims out even '\0' inline std::string& trim_right(std::string& s); // ..along with \r\n\t and SPACE inline std::string& trim(std::string& s); // inline std::string& trim_to_cpp_string(std::string& s); // adjust the length of string to trailing '\0' inline std::string& make_upper_case(std::string& s); // inline std::string& make_lower_case(std::string& s); // //inline std::string& replace(std::string&s, const std::string&fs,const std::string&rs=std::string(), size_t ntimes=-1); class char_less_than_ignore_case; // the case-insensitive predicates class char_equal_ignore_case; // .. to compare string, char, class char_less_equal_ignore_case; // .. and *char template class ichar_traits; // traits to make nocase strings //typedef basic_string istring; // .. and ignore case string std::string int_to_string(int i, int radix); template // string-string parser class string_pair_parser; typedef string_pair_parser<'&', '=', // HTTP POST data std::map > HTTP_POST_data; typedef string_pair_parser<'&', '=', // HTTP QueryString std::map > HTTP_query_string; typedef string_pair_parser<'\n', ':', std::map > HTTP_headers; template class HTTP_cookie_base; class HTTP_cookie; // HTTP COOKIE. (case insesitive key) class HTTP_dictinary_cookie; // HTTP dictionary COOKIE. (case insesitive key) class HTTP_dictionary_cookie_with_dependencies; // ditto.. plus read-only/read-once keys and dependencies template struct CSV; // Comma-separted-values format.. class CSV_parser; // ..CSV<"\\"> makes backslash separated format templateclass referenced; // templateclass handle; // templateclass statistics; // templateclass array; // class CTimer; // timer to class FileTime; // wrappers on SYSTEMTIME, FILETIME class SystemTime; class EventStream; // C++ stream complain ::ReportEvent class OutputDebugStream; // C++ stream complain ::OutputDebugString class TraceStream; // Tracer works along with OutputDebugStream class URL; // ::Internet(Create/Crack/Canonicalize/Combine)URL. class HTML; // stringstream to generate an HTML page class clsid; // CLSID wrapper class progid; // CLSID wrapper with ProgId support class CTextOfError_Formatter; // generating standard types into XML text error class CRuntime_error; // class CSeExceptionsTranslator; // WIN32 SE exception hook class XMLAttribute; // class XMLElement; // class CStatistics; // thread safe statistics class semaphore; // simple semaphore +- 1 class RegistryKey; // HKEY class text_files_cache; // read-in cache of text files class text_file; // text file content with insert/replace extensions class ThisComputer; // Information on THIS computer class FileInformation; // WIN32_FIND_DATA wrapper class FileVersion; // VS_FIXEDFILEINFO (version information) wrapper class InternetExplorer; // Microsoft Internet Explorer class critical_section_variable; class critical_section; class general_critical_section; class CO_initialize; typedef std::pair string_pair; // alias of string-string pair typedef std::vector string_vector; // // Registry::type employeeRoster; // Registry::type callbacks; // Registry::type factories; // template struct Registry { typedef std::map type; }; // // NOTES: Some of those classes have the static variables (DebugOutputStream::disabled, // GeneralCriticalSection::m_pcs). The C++ language guarantees to initialize // a static variable once on the first use of it; and if you dont cache in an ISAPI extension // the static variable will always be initialized on using your extension (it shall be loaded // in memory space over and over) // ///////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// // // STL unary function that does not transformation (to be used in algorithms that need // transformers) // template struct do_nothing : public std::unary_function { T operator() (T t) { return t; } }; ///////////////////////////////////////////////////////////////////////////////////////// // // cast is a functor object that takes one argument (pointer to some class) // and returns a pointer to the member of this structure. In opposite to dynamic_cast<> // throws no std::bad_cast but returns 0 in no casting case. // template class cast : public std::unary_function { public: TMember operator()(TStruct Structure) const throw() { #ifdef __RTTI__ try { return dynamic_cast(Structure); } catch(...) //std::bad_cast) { return 0; } #else return static_cast(Structure); #endif } template<>std::string operator()(char*p) const throw(){return p?std::string(p):std::string();} template<>std::string operator()(const char*p) const throw(){return p?std::string(p):std::string();} template<>std::string operator()(unsigned char*p) const throw(){return p?std::string(p):std::string();} template<>std::string operator()(const unsigned char*p) const throw(){return p?std::string(p):std::string();} template<>std::string operator()(const _bstr_t b) const throw(){char*p=(char*)b;return p?std::string(p):std::string();} // template<>std::string operator()(_bstr_t b) const throw(){return cast((char*)b);} }; template dst lexical_cast(const src& arg) throw(CRuntime_error) { std::stringstream translator; dst result; if(!(translator << arg) || !(translator >> result) || !(translator >> std::ws).eof()) throw CRuntime_error("Source: lexical_cast", "There is no conversion from src to dst"); return result; } template dst script_cast(const src& arg) { std::stringstream translator; dst result; if(!(translator << arg) || !(translator >> result) || !(translator >> std::ws).eof()) return dst(); return result; } template dst string_to(const std::string& arg) { std::istringstream translator(arg); dst result; if(!(translator >> result)) // || !(translator >> std::ws).eof()) return dst(); return result; } inline std::string int_to_string(int i, int radix=10) { char buf[50]; return ::itoa(i, buf, radix); } inline std::string long_to_string(long i, int radix=10) { char buf[50]; return ::_ltoa(i, buf, radix); } inline std::string stringer(int i, int radix=10) {return int_to_string(i, radix);} inline std::string stringer(long i, int radix=10) {return long_to_string(i, radix);} inline std::string stringer(char*p) {return p?std::string(p):std::string();} inline std::string stringer(const char*p) {return p?std::string(p):std::string();} inline std::string stringer(unsigned char*p) {return p?std::string((char*)p):std::string();} inline std::string stringer(const unsigned char*p) {return p?std::string((char*)p):std::string();} inline std::string stringer(const _bstr_t& b) {char*p=(char*)b;return p?std::string(p):std::string();} inline std::string stringer(BSTR bstr) { std::string s(::SysStringLen(bstr), '\0'); ::wcstombs(const_cast(s.data()), bstr, s.length()); return s; } inline std::string stringer(VARIANT& vi) //, const char* beg="", const char* end="") { std::string r; try{ _variant_t v(vi); v.ChangeType(VT_BSTR); r+=stringer(v.bstrVal); }catch(...) {} return r; } inline char* cstringer(char*p) {return p?(char*) p:"";} inline char* cstringer(const char*p) {return p?(char*) p:"";} inline char* cstringer(unsigned char*p) {return p?(char*) p:"";} inline char* cstringer(const unsigned char*p) {return p?(char*) p:"";} inline BSTR cstring_to_BSTR(const char* s) { if(s==0) return 0; int sLen = ::strlen(s); #if defined(_UNICODE) || defined(OLE2ANSI) BSTR bstr = ::SysAllocStringLen(s, sLen); #else int nLen = ::MultiByteToWideChar(CP_ACP, 0, s, sLen, 0, 0); BSTR bstr = ::SysAllocStringLen(0, nLen); if(bstr != 0) ::MultiByteToWideChar(CP_ACP, 0, s, sLen, bstr, nLen); #endif return bstr; } inline BSTR string_to_BSTR(const std::string& s) { #if defined(_UNICODE) || defined(OLE2ANSI) BSTR bstr = ::SysAllocStringLen(s.data(), s.length()); #else int nLen = ::MultiByteToWideChar(CP_ACP, 0, s.data(), s.length(), 0, 0); BSTR bstr = ::SysAllocStringLen(NULL, nLen); if(bstr != 0) ::MultiByteToWideChar(CP_ACP, 0, s.data(), s.length(), bstr, nLen); #endif return bstr; } //////////////////////////////////////////////////////////////////////////////////////// // // makes a T struct STL compatible. Notes derived classes cannot use = operators // template struct STL_adapter : public T { STL_adapter() { zerroing(); } STL_adapter(const T& t) { assign(t); } STL_adapter(const STL_adapter& t) { assign(t); } STL_adapter& assign(const STL_adapter& t){ ::memcpy(static_cast(this), static_cast(&t), sizeof T); return *this; } STL_adapter& assign(const T& t) { ::memcpy(static_cast(this), &t, sizeof T); return *this; } STL_adapter& operator=(const STL_adapter& t) { return assign(t); } STL_adapter& operator=(const T& t) { return assign(t); } void zerroing() { ::memset(static_cast(this), 0, sizeof T); } void init() { zerroing(); } // // comparisions // bool operator==(const T& x) const { return ::memcmp(static_cast(this), &x, sizeof T) ==0; } bool operator!=(const T& x) const { return ::memcmp(static_cast(this), &x, sizeof T) !=0; } bool operator==(const STL_adapter& x)const { return *this == static_cast(x); } bool operator!=(const STL_adapter& x)const { return *this != static_cast(x); } }; //////////////////////////////////////////////////////////////////////////////////////// // // Usefull funcs std::string lacks of (trimming whitespaces, and converting a string to // upper/lower case). STL-complaint binary functor to compare two string ignoring // case (see sample of using it in HTTP_cookie class) // inline std::string& trim_left(std::string& s) { int n=s.find_first_not_of("\t\r\n ", 0, sizeof "\t\r\n "); if(n != std::string::npos) s.erase(0, n); return s; } inline std::string& trim_right(std::string& s) { int n=s.find_last_not_of("\t\r\n ", std::string::npos, sizeof "\t\r\n "); if(n != std::string::npos) s.erase(n+1); return s; } inline std::string& trim(std::string& s) { return trim_right(trim_left(s)); } inline std::string& trim_to_cpp_string(std::string& s) // erases string after '\0' symbol { std::string::iterator it =std::find(s.begin(), s.end(), '\0'); if(it !=s.end()) s.erase(it, s.end()); return s; } inline std::string& make_upper_case(std::string& s) { for(std::string::iterator i=s.begin() ; i != s.end() ; ++i) *i = ::toupper(*i); return s; } inline std::string& make_lower_case(std::string& s) { for(std::string::iterator i=s.begin() ; i != s.end() ; ++i) *i = ::tolower(*i); return s; } inline std::string& make_printable(std::string& s, const char chToReplace='?') { for(std::string::iterator i=s.begin() ; i != s.end() ; ++i) if(!::isprint(*i) && *i !='\t' && *i !='\n' && *i !='\r') // allow tab/cr/lf to be printed *i = chToReplace; return s; } inline std::string& replace(std::string& s, const std::string&fs, const std::string&rs=std::string(), size_t ntimes=-1) { for(size_t i=0 , p=0 ; i class ichar_traits : public std::char_traits { public: static bool eq(const E& c1, const E& c2) { return ::toupper(c1) == ::toupper(c2); } static bool lt(const E& c1, const E& c2) { return ::toupper(c1) < ::toupper(c2); } static int compare(const E* s1, const E* s2, size_t n) { if(s1 !=s2) { if(s2 ==0) return +1; if(s1 ==0) return -1; for(size_t i =0 ; i < n ; ++i) if(!eq(s1[i], s2[i])) return lt(s1[i], s2[i])? -1 : +1; } return 0; } static const E* find(const E* s1, size_t n, const E& c) { if(s1 !=0) for(size_t i =0 ; i < n ; ++i) if(eq(s1[i], c)) return &s1[i]; return 0; } }; //////////////////////////////////////////////////////////////////////////////////////////////////// // // A Win32's DLL has its very own heap of memory, which is accessible by the DLL itself and by the // process that has linked to the DLL. Other DLLs in the process though do NOT have access to any of // other DLL's heaps but itself's (so called cross-DLLs bounderies). In order to be able to pass // over the C++ objects from a DLL to a DLL they have to use different to default operator // new/delete memory management (new/delete is implemented via C malloc/free that are use local DLL's // heap). // The following are 2 C++ allocators allowing safely pass over C++ object between DLLs and COM-based // * The Win32 Alloc functions have the advantage that they can safely be // used accross module (dll) boundaries (not implemented yet) // * allocator using the process heap (the memory goes through DLL boundaries) // * allocator using the default OLE allocator. Works well in either C, C++, or Visual Basic. It is // also the only way to share memory in a COM-based application, since MIDL uses CoTaskMemAlloc // and CoTaskMemFree to marshal memory. // //templateinline T* new_allocate_HeapAlloc(size_type N, const void*) { return (T*)::HeapAlloc(::GetProcessHeap(), 0, N*sizeof(T)); } templateinline void new_construct_HeapAlloc(T* p, const T& v) { new((void*)p) T(v); } templateinline void new_destroy_HeapAlloc(T* p) { if(p) p->~T(); } //templateinline void new_deallocate_HeapAlloc(void* p, size_type) { if(p) ::HeapFree(::GetProcessHeap(), 0, p); } // { operator delete(p); } template class process_heap_allocator { HANDLE _hProcessHeap; // inline T* _Allocate(size_t N, T*) { return (T*) ::operator new(N*sizeof(T)); } public: typedef size_t size_type; typedef ptrdiff_t difference_type; typedef T* pointer; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; typedef T value_type; process_heap_allocator() : _hProcessHeap(::GetProcessHeap()) { ; } process_heap_allocator(const process_heap_allocator& x) : _hProcessHeap(x._hProcessHeap) { ; } process_heap_allocator& operator=(const process_heap_allocator& x) { _hProcessHeap =x._hProcessHeap; return *this; } ~process_heap_allocator() {} pointer address(reference _X) const {return &_X; } const_pointer address(const_reference _X) const {return &_X; } pointer allocate(size_type N, const void*) {return (pointer)::HeapAlloc(_hProcessHeap, 0, N*sizeof(T)); } // char* _Charalloc(size_type N) {return (char*) ::HeapAlloc(_hProcessHeap, 0, N*sizeof(char)); } void deallocate(void* p, size_type) { if(p) ::HeapFree(_hProcessHeap, 0, p); } // { operator delete(p); } void construct(pointer p, const T& v) { new((void*)p)T(v); } void destroy(pointer p) { p->~T(); } size_t max_size() const {size_t n = (size_t)(-1) / sizeof (T); return n>0? n : 1; } }; template inline bool operator==(const process_heap_allocator&, const process_heap_allocator&) { return true; } template inline bool operator!=(const process_heap_allocator&, const process_heap_allocator&) { return false; } //Header: Declared in objbase.h. template class COM_allocator { public: typedef size_t size_type; typedef ptrdiff_t difference_type; typedef T* pointer; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; typedef T value_type; COM_allocator () {} COM_allocator (const process_heap_allocator&) {} COM_allocator& operator=(const COM_allocator&) { return *this; } ~COM_allocator () {} pointer address(reference _X) const {return &_X; } const_pointer address(const_reference _X) const {return &_X; } pointer allocate(size_type N, const void*) {return (pointer) ::CoTaskMemAlloc(N*sizeof(T)); } // char* _Charalloc(size_type N) {return (char*) ::CoTaskMemAlloc(N*sizeof(char)); } void deallocate(void* p, size_type) { if(p) ::CoTaskMemFree(p); } // { operator delete(p); } void construct(pointer p, const T& v) { new((void*)p)T(v); } void destroy(pointer p) { p->~T(); } size_t max_size() const {size_t n = (size_t)(-1) / sizeof (T); return n>0? n : 1; } }; template inline bool operator==(const COM_allocator&, const COM_allocator&) { return true; } template inline bool operator!=(const COM_allocator&, const COM_allocator&) { return false; } //////////////////////////////////////////////////////////////////////////////////////////////////// // typedef std::basic_string, process_heap_allocator > process_heap_string; typedef std::basic_string, process_heap_allocator > process_heap_istring; typedef std::basic_string, COM_allocator > COM_string; typedef std::basic_string, COM_allocator > COM_istring; #ifdef _DLL #pragma warning(disable:4231) /* the extern before template is a non-standard extension */ extern template class GYS_SPEC std::basic_string, process_heap_allocator >; extern template class GYS_SPEC std::basic_string, process_heap_allocator >; extern template class GYS_SPEC std::basic_string, COM_allocator >; extern template class GYS_SPEC std::basic_string, COM_allocator >; #pragma warning(default:4231) /* restore previous warning */ #endif // _DLL // class GYS_SPEC char_less_than_ignore_case // : public std::binary_function { { // mutable bool bRes; public: char_less_than_ignore_case() {} //: bRes(false) {} // char_less_than_ignore_case(const char c1, const char c2) : bRes(compare(c1,c2)) {} // char_less_than_ignore_case(const std::string& s1, const std::string& s2) : bRes(compare(s1,s2)) {} // char_less_than_ignore_case(const char*s1b,const char*s1e,const char*s2b,const char*s2e) : bRes(compare(s1b,s1e,s2b,s2e)) {} // operator bool() const { return bRes; } bool operator() (const char c1, const char c2) const { return compare(c1,c2); } bool operator() (const std::string& s1, const std::string& s2) const { return compare(s1, s2); } bool operator() (const char*s1b,const char*s1e,const char*s2b,const char*s2e) const { return compare(s1b,s1e,s2b,s2e); } static bool compare_symbols(const char c1, const char c2) { return ::toupper(c1) < ::toupper(c2); } static bool compare(const char c1, const char c2) { return compare_symbols(c1,c2); } static bool compare(const std::string& s1, const std::string& s2) { return std::lexicographical_compare(s1.begin(), s1.end(), s2.begin(), s2.end(), compare_symbols); } static bool compare(const char* s1b, const char* s1e, const char* s2b, const char* s2e) { return std::lexicographical_compare(s1b, s1e, s2b, s2e, compare_symbols); } // char_less_than_ignore_case& operator =(const char_less_than_ignore_case& x) { return *this; } // char_less_than_ignore_case(const char_less_than_ignore_case& x) { } }; class GYS_SPEC char_equal_ignore_case { const bool bRes; static bool compare_symbols(const char c1, const char c2) { return ::toupper(c1) == ::toupper(c2); } public: // char_equal_ignore_case() : bRes(false){} char_equal_ignore_case(const char c1, const char c2) : bRes(compare(c1,c2)) { ; } char_equal_ignore_case(const std::string& s1, const std::string& s2): bRes(compare(s1,s2)) { ; } char_equal_ignore_case(const char* s1, const char* s2) : bRes(compare(s1,s2)) { ; } char_equal_ignore_case(const std::string& s1, const char* s2) : bRes(compare(s1,s2)) { ; } char_equal_ignore_case(const char* s1, const std::string& s2) : bRes(compare(s1,s2)) { ; } operator bool() const { return bRes; } static bool compare(const char c1, const char c2) { return compare_symbols(c1,c2); } static bool compare(const std::string& s1, const std::string& s2) { return s1.length() == s2.length() && std::equal(s1.begin(), s1.end(), s2.begin(), compare_symbols); } static bool compare(const char* s1, const char* s2) { if(s1==s2) return true; if(s1 ==0 || s2 ==0) return false; for( ; *s1 !='\0' && *s2 !='\0' && compare_symbols(*s1,*s2) ; ++s1 , ++s2) ; return *s1 == '\0' && *s2 =='\0'; } static int compare(const char* s1, const char* s2, size_t max_len) { return ichar_traits::compare(s1, s2, max_len); } static bool compare(const std::string& s1, const char* s2) { return compare(s1.c_str(), s2); } static bool compare (const char* s1, const std::string& s2) { return compare(s1, s2.c_str()); } }; typedef std::basic_string > istring; // .. and ignore case string inline std::ostream& operator<< (std::ostream& s, const istring& str) { return s << str.c_str(); } ////////////////////////////////////////////////////////////////////////////////////////// // // functor for converting the Visual C++ types that they claim to be a standard into // HTML text. It is XML well-formed ready. Here is a sample of such XML: // // some text // Type: some type (for example HRESULT) // Type: some more type information (for example SUCCESS OK) // Description: some description text // some more description text // Source: source of the error // Source: some more info on source of the error // Line: Line where the error has occured // Position: Position in line where the error has occured // // class GYS_SPEC CTextOfError_Formatter { std::ostringstream s; const char *prfx; public: CTextOfError_Formatter(const char _prfx[]=0); CTextOfError_Formatter(const std::string& _prfx); template CTextOfError_Formatter& operator<< (T t) { s << t; return *this; } template<> CTextOfError_Formatter& operator<< (_bstr_t t) { s << (char*) t; return *this; } operator std::string () { return s.str(); } #if defined _MFC_VER std::string getText(CException* e); #endif std::string getText(const char *er); std::string getText(DWORD er); std::string getText(HRESULT hr); std::string getText(const _com_error& er); std::string getText(const URL& er); std::string getText(const std::exception& er); std::string textOfWin32Error(DWORD error_code=-1); private: void textOfCOMError(const _com_error& er) throw(); }; ////////////////////////////////////////////////////////////////////////////////////////// // // inline funcs-helpers for converting all the Visual C++ types that they claim to be // standard into HTML text. Is used along with templatized constructor of CRuntime_error. // #if defined _MFC_VER inline std::string textOfError(const char prfx[], CException* e) { return CTextOfError_Formatter(prfx).getText(e); } inline std::string textOfError(const std::string prfx, CException* e) { return CTextOfError_Formatter(prfx).getText(e); } #endif inline std::string textOfError(const char prfx[], const char * e) { return CTextOfError_Formatter(prfx).getText(e); } inline std::string textOfError(const std::string prfx, const char * e) { return CTextOfError_Formatter(prfx).getText(e); } inline std::string textOfError(const char prfx[], const HRESULT e) { return CTextOfError_Formatter(prfx).getText(e); } inline std::string textOfError(const std::string prfx, const HRESULT e) { return CTextOfError_Formatter(prfx).getText(e); } inline std::string textOfError(const char prfx[], const URL& e) { return CTextOfError_Formatter(prfx).getText(e); } inline std::string textOfError(const std::string prfx, const URL& e) { return CTextOfError_Formatter(prfx).getText(e); } inline std::string textOfError(const char prfx[], DWORD e) { return CTextOfError_Formatter(prfx).getText(e); } inline std::string textOfError(const std::string prfx, DWORD e) { return CTextOfError_Formatter(prfx).getText(e); } inline std::string textOfError(const char prfx[], const _com_error& e) { return CTextOfError_Formatter(prfx).getText(e); } inline std::string textOfError(const std::string prfx, const _com_error& e) { return CTextOfError_Formatter(prfx).getText(e); } inline std::string textOfError(const char prfx[], const std::exception&e) { return CTextOfError_Formatter(prfx).getText(e); } inline std::string textOfError(const std::string prfx, const std::exception&e) { return CTextOfError_Formatter(prfx).getText(e); } ////////////////////////////////////////////////////////////////////////////////////////// // // std::exception extension to convert various 'standard' Windows errors into plain english // in HTML format. The following are some of the features std::*_error (std::runtime_error, // std::logic_error and so on) lack of: // -- it uses all the Visual C++ types that they claim to be standard. // -- it may be a base class for derivation. // -- it has a template constructor that calls textOfError so you can easely extend // the types of errors it manages // // To define new type of the error you have to write new textOfError function. F.e. // MSXML error may be represented with the next function: // // std::string textOfError(const char prfx[], MSXML::IXMLDOMParseErrorPtr pError) { // std::string s(prfx); // s += (char*)pError->reason; // return s; // } // // so you may throw to exception using the same CRuntime_error class: // // throw CRuntime_error("XSLT transformtion error: ", stylesheetPtr->GetparseError()); // class GYS_SPEC CRuntime_error : public std::exception { public: operator _bstr_t () const { return _bstr_t(_strText.c_str()); } operator const char* () const { return _strText.c_str(); } std::string& operator() () { return _strText; } std::string operator() () const { return _strText; } virtual const char* what() const { return _strText.c_str(); } bool empty () const { return _strText.empty(); } void erase() { _strText.erase(); } CRuntime_error() {;} CRuntime_error(const char desc[]) : _strText(desc) {;} CRuntime_error(const std::string& desc) : _strText(desc) {;} CRuntime_error(const CRuntime_error& other) { *this=other;} template CRuntime_error(T t, E e) throw() { try { _strText ="" +textOfError(t, e)+""; } catch(...) { #if 1 // defined(_CPPRTTI) _strText.append("Runtime-error
Description: Exception in CRuntime_error(") .append(typeid(T).name()) .append(", ") .append(typeid(E).name()) .append(")
"); #else _strText = "Runtime-error
Description: Exception in CRuntime_error(T, E)
"; #endif } } template CRuntime_error& operator=(const T& t) { try { _strText.append("Runtime-error
") .append(textOfError("Note: The error has been casted to CRuntime_error
", t)) .append("
Type of caught error: ") .append(typeid(T).name()) .append("
"); } catch(...) { #if 1 // defined(_CPPRTTI) _strText.append("Runtime-error
Description: Exception on CRuntime_error::operator=(") .append(typeid(T).name()) .append(")
"); #else _strText = "Runtime-error
Description: Exception on CRuntime_error::operator=(T)
"; #endif } return *this; }; CRuntime_error& operator=(const CRuntime_error& other) { _strText = other._strText; return *this;} // // the methods to get the parts of the error // std::string operator[] (const char* sectionname) const { return extract(sectionname); } std::string extract(const char* sectionname) const; std::string text() const; // removes tags GYS_SPEC std::string getContentAsHtml(const TraceStream* pts=0) const; GYS_SPEC std::string getContentAsHtml(const TraceStream& ts) const;// { return getContentAsHtml(&ts); } protected: std::string _strText; }; /////////////////////////////////////////////////////////////////////////////////////////////////// // // translator of the SE exceptions into CRuntime_error. On constructor hooks up SE, on destructor // restores the original one. Does not hook the debug interrupts in DEBUG version // #define SeExceptionsTranslator() CSeExceptionsTranslator UNIQUE_VARIABLE class GYS_SPEC CSeExceptionsTranslator { public: explicit CSeExceptionsTranslator() { se_translator_processor(1,0); } ~CSeExceptionsTranslator() { se_translator_processor(0,0); } private: static void __cdecl SeTranslator(UINT nSeCode, _EXCEPTION_POINTERS* pExcPointers) throw(CRuntime_error); static void se_translator_processor(unsigned int nSeCode, struct _EXCEPTION_POINTERS* pExcPointers); CSeExceptionsTranslator(const CSeExceptionsTranslator& se) {} CSeExceptionsTranslator& operator= (const CSeExceptionsTranslator& se) {return *this;} }; /////////////////////////////////////////////////////////////////////////////// // // A Critical section macro-variable and the using of this variable that are wrapped // with classes. These are to be used as // // CriticalSectionVariable g_csVar; // better put it in global namespace // .... // // the next code in braces are guarded by critical section // { // CriticalSection (g_csVar); // ... // } // // This class has workaround the next Win32 potential problem: If a thread calls // LeaveCriticalSection when it does not have ownership of the specified critical section // object, an error occurs that may cause another thread using EnterCriticalSection to // wait indefinitely // class GYS_SPEC critical_section_variable : public CRITICAL_SECTION { public: critical_section_variable() { ::InitializeCriticalSection(static_cast (this)); } virtual ~critical_section_variable() { ::DeleteCriticalSection(static_cast (this)); } LPCRITICAL_SECTION operator& () { return static_cast (this); } }; class GYS_SPEC critical_section { public: explicit critical_section(CRITICAL_SECTION &pcs) : m_pcs(&pcs) , _cnt(0) { lock(); } explicit critical_section(critical_section_variable &pcs) : m_pcs(&pcs) , _cnt(0) { unlock(); } virtual ~critical_section() { while(unlock()) ; } bool unlock() { return (--_cnt) >=0? ::LeaveCriticalSection(m_pcs) , true : _cnt=0 , false; } void lock() { ::EnterCriticalSection(m_pcs); ++_cnt; } private: // explicit critical_section(CComAutoCriticalSection &pcs) : m_pcs(&pcs.m_sec) { ::EnterCriticalSection(m_pcs); } LPCRITICAL_SECTION m_pcs; int _cnt; // // this class is a wrapper on Crit.section. Don't us it as // CCriticalSection(some_cs_variable); // Do use it declaring a variable, for example // CCriticalSection cs(some_cs_variable); // Consider using CriticalSection macro instead (one generates an unique name for you) // critical_section() {;} // see above comment. critical_section(const critical_section&) {;} // This does not make any sense for CS critical_section& operator=(const critical_section&) {return *this;} // ..ditto }; //////////////////////////////////////////////////////////////////////////////// // // An interface on critical section for general use. In old good times we used // to use the disable/enable interrupt instructions (DI/EI) in place of that // class GYS_SPEC general_critical_section : public critical_section { static critical_section_variable m_cs; public: explicit general_critical_section() : critical_section(m_cs) {;} }; ///////////////////////////////////////////////////////////////////////////////////////// // // small helper-wrapper on CoInitialize/CoUnitialize // use ComLibraryInitialize macros instead // throws to CRuntime_error on failing of initialization // class GYS_SPEC CO_initilize { public: CO_initilize(DWORD dwCoInit=COINIT_APARTMENTTHREADED) throw(CRuntime_error) { //hr = ::CoInitializeEx(0, dwCoInit); // ?? It is not get included if(FAILED(hr = ::CoInitialize(0))) throw CRuntime_error("Note: CoInitialize failed", hr); } virtual ~CO_initilize() { if(SUCCEEDED(hr)) ::CoUninitialize(); } operator HRESULT() const { return hr; } private: HRESULT hr; CO_initilize(const CO_initilize&) {} CO_initilize& operator= (const CO_initilize&) { return *this; } }; ///////////////////////////////////////////////////////////////////////////////////////// // // small helper-wrapper on CoInitialize/CoUnitialize // use ComLibraryInitialize macros instead // throws to CRuntime_error on failing of initialization // class GYS_SPEC CCoInitialize { public: CCoInitialize(DWORD dwCoInit=COINIT_APARTMENTTHREADED) throw(CRuntime_error) { if(FAILED(hr = ::CoInitialize(0))) throw CRuntime_error("Note: CoInitialize failed", hr); } virtual ~CCoInitialize() { if(SUCCEEDED(hr)) ::CoUninitialize(); } operator HRESULT() const { return hr; } private: HRESULT hr; CCoInitialize(const CCoInitialize&) {} CCoInitialize& operator= (const CCoInitialize&) { return *this; } }; //////////////////////////////////////////////////////////////////////////////////////// // // functor to convert memory to a hex dump // class GYS_SPEC dump { public: dump(const void* pb, const void *pe, const int line_len=16, const bool bAscii=true); dump(const void* p, const int len, const int line_len=16, const bool bAscii=true); dump(const char* p, const int line_len=16, const bool bAscii=true); dump(const unsigned char* p, const int line_len=16, const bool bAscii=true); dump(const std::string& s, const int line_len=16, const bool bAscii=true); std::ostream& operator() (std::ostream& s); static std::ostream& dump_hex(std::ostream& os, const unsigned char* b, int len); private: bool doit(const unsigned char* pcur_) const; // returns true if pcur_ in the buffer const unsigned char *pbeg_, *pend_; const int line_len_; const unsigned char terminator_; const bool bAscii_; }; inline std::ostream& operator<< (std::ostream& s, dump& d) { return d(s); } //////////////////////////////////////////////////////////////////////////////////////// // // timer to evaluate duration (in mls) of timing processes // class GYS_SPEC CTimer { clock_t _start; public: CTimer() { start(); } void start() { _start = ::clock(); } long current_value() const { return ((double)(::clock()-_start)/CLOCKS_PER_SEC*1000.0); } long operator() () const { return current_value(); } long stopwatch() { return restartwatch(); } long restartwatch() { long now = ::clock(); long ret = ((double)(now - _start) / CLOCKS_PER_SEC *1000.0); _start = now; return ret; } static std::string strLocalTime(time_t t, const char* pszFormat="%#c") { struct tm *tmtime = ::localtime(&t); char tmpbuf[128]; ::strftime(tmpbuf, sizeof(tmpbuf) -1, pszFormat, tmtime); return tmpbuf; } static std::string strUTCTime(time_t t, const char* pszFormat="%#c") { struct tm *tmtime = ::gmtime(&t); char tmpbuf[256]; ::strftime(tmpbuf, sizeof(tmpbuf) -1, pszFormat, tmtime); return tmpbuf; } static std::string strCurrentTime(const char* pszFormat="%#c") { return strLocalTime(::time(0), pszFormat); } static std::string strGMTExpirationTime(long secsExpire, const char* pszFormat="%a %d-%b-%Y %H:%M:%S GMT") { return strUTCTime(::time(0) +secsExpire, pszFormat); } // // system time // static std::string SystemTimeAsString(const SYSTEMTIME& st) { static const char *weekdays[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; static const char *months[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; std::ostringstream s; s << weekdays[st.wDayOfWeek%7] << ", " << months[(st.wMonth-1)%12] << " " << st.wDay << ", " << st.wYear << " " << st.wHour << ":" << st.wMinute << ":" << st.wSecond << "'" << st.wMilliseconds <<"\""; return s.str(); } static std::string SystemTimeAsHtml(const SYSTEMTIME& ft) { std::string s(SystemTimeAsString(ft)); return s.empty()? std::string(" ") : s; } // // returns LOCAL file time // static std::string FileTimeAsString(const FILETIME& f) { FILETIME ft; if((f.dwLowDateTime==0 && f.dwHighDateTime==0) || !::FileTimeToLocalFileTime(&f, &ft)) return ""; SYSTEMTIME st; return ::FileTimeToSystemTime(&ft, &st)? SystemTimeAsString(st) : std::string(); } static std::string FileTimeAsHtml(const FILETIME& ft) { std::string s(FileTimeAsString(ft)); return s.empty()? std::string(" ") : s; } }; ///////////////////////////////////////////////////////////////////////////////////////// // // FileTime SystemTime wrappers // class GYS_SPEC FileTime : public FILETIME { public: FileTime(DWORD lowTime=0, DWORD highTime=0) { dwLowDateTime =lowTime; dwHighDateTime =highTime; } FileTime(const FileTime& t) { *this = t; } FileTime(const FILETIME& t) { *this = t; } FileTime(const SYSTEMTIME& t) { *this = t; } FileTime& operator= (const FileTime& t) { dwLowDateTime = t.dwLowDateTime; dwHighDateTime = t.dwHighDateTime; return *this; } FileTime& operator= (const FILETIME& t) { dwLowDateTime = t.dwLowDateTime; dwHighDateTime = t.dwHighDateTime; return *this; } FileTime& operator= (int t) { if(t ==0) erase(); return *this; } FileTime& operator= (const SYSTEMTIME& t) { erase(); ::SystemTimeToFileTime(&t, static_cast(this)); return *this; } FileTime GetLocalFileTime() const { FILETIME t={0,0}; ::FileTimeToLocalFileTime(static_cast(this), &t); return t; } static FileTime GetSystemTime() { FILETIME t={0,0}; ::GetSystemTimeAsFileTime(&t); return t; } unsigned long mls() const { //#define INT64_FROM_FILETIME(li) (*((__int64 *)&(li))) __int64 i64 = *((__int64 *)(static_cast(this) )); i64 /=10000; // make a milliseconds from 100 nanoseconds return (unsigned long) i64; } operator SystemTime () const; void erase() { dwLowDateTime =0; dwHighDateTime =0; } std::string AsString() const { return CTimer::FileTimeAsString(static_cast(*this)); } std::string AsHtml() const { return CTimer::FileTimeAsHtml(static_cast(*this)); } operator std::string () { return CTimer::FileTimeAsString(static_cast(*this)); } }; class GYS_SPEC SystemTime : public SYSTEMTIME { public: SystemTime() { GetSystemTime(); } SystemTime(int t) { erase(); } SystemTime(const SystemTime& t) { *this = t; } SystemTime(const SYSTEMTIME& t) { *this = t; } SystemTime(const FILETIME& t) { *this = t; } SystemTime& operator= (const SystemTime& t) { ::memcpy(static_cast(this), static_cast(&t), sizeof SYSTEMTIME); return *this; } SystemTime& operator= (const SYSTEMTIME& t) { ::memcpy(static_cast(this), &t, sizeof SYSTEMTIME); return *this; } SystemTime& operator= (int t) { if(t ==0) erase(); return *this; } SystemTime& operator= (const FILETIME& t) { erase(); ::FileTimeToSystemTime(&t, static_cast(this)); return *this; } operator FileTime () const { FileTime t(static_cast(*this)); return t; } SystemTime& GetSystemTime() { ::GetSystemTime(static_cast(this)); return *this; } void erase() { ::memset(static_cast(this), 0, sizeof SYSTEMTIME); } std::string SystemTimeAsString() const { return CTimer::SystemTimeAsString(static_cast(*this)); } std::string SystemTimeAsHtml() const { return CTimer::SystemTimeAsHtml(static_cast(*this)); } operator std::string () { return SystemTimeAsString(); } }; inline FileTime::operator SystemTime () const { return SystemTime(static_cast(*this)); } ///////////////////////////////////////////////////////////////////////////////////////// // // Reference counted object(s) and its pointer. Thread safe in terms of assignment // // 1. reference_counter itself. GYS: I use even 'pack(8)' to place 'counter__' on 'long' // boundary to satisfy 'Interloked*' when it shall become __int64. For 32 machine // it's enough to 'pack(4)' // 2. rcimpl_base_signature. (R)ef(C)ounted PIMPL to distinguish from reference_counter // 3. rcp. (R)eference (C)ounted (P)ointer // // Sample of using: // // rcp p; // p.create_new(arg1, arg2, arg3); // create brand new 'object' through 'p' // rcp p2 = p; // p2 has access to to the same 'object' as p // #pragma pack(push, multithread_alignment_depended_part, 8) class GYS_SPEC reference_counter { public: reference_counter() : counter__(1) {;} virtual ~reference_counter() throw(std::domain_error) { if(counter__ !=0) throw std::domain_error("reference_counter::~reference_counter(). counter__ ="); } void add_reference() { ::InterlockedIncrement(&counter__); } void release() { if(::InterlockedDecrement(&counter__) <=0) destroy(); } long number_of_references() const { return counter__; } protected: reference_counter(const reference_counter& x){} reference_counter& operator= (const reference_counter& x){ return *this; } virtual void destroy() { delete this; } long counter__; }; ///////////////////////////////////////////////////////////////////////////////////////// // class GYS_SPEC rcimpl_base_signature : protected reference_counter { public: using reference_counter::number_of_references; virtual operator void*() const { return 0; } protected: ~rcimpl_base_signature() {} // This class is to be used only as a base for rcp::impl }; ///////////////////////////////////////////////////////////////////////////////////////// // template class rcp { public: rcp() : pc_(0) , pt_(0) {} rcp(const rcp& x) : pc_(x.pc_) , pt_(x.pt_) { add_reference(); } rcp(const rcimpl_base_signature& x) : pc_(0) , pt_(0) { *this =x; } ~rcp() { release(); } /* templatercp(T1 t1) :pt_(new T(t1)) {} templatercp(T1 t1,T2 t2) :pt_(new T(t1,t2)) {} templatercp(T1 t1,T2 t2,T3 t3) :pt_(new T(t1,t2,t3)) {} templatercp(T1 t1,T2 t2,T3 t3,T4 t4) :pt_(new T(t1,t2,t3,t4)){} */ templatercp(T1 t1) :pt_(new T(t1)) {} templatercp(T1 t1,T2 t2) :pt_(new T(t1,t2)) {} templatercp(T1 t1,T2 t2,T3 t3) :pt_(new T(t1,t2,t3)) {} templatercp(T1 t1,T2 t2,T3 t3,T4 t4) :pt_(new T(t1,t2,t3,t4)){} operator rcimpl_base_signature* () const { return pc_; } rcp& operator=(const rcp& x) throw() { release(); pc_ =x.pc_; add_reference(); pt_ =x.pt_; return *this; } rcp& operator=(const rcimpl_base_signature& x) throw() { release(); try { if((pt_ = dynamic_cast((void*)x)) !=0) { pc_ =&x; add_reference(); } } catch(...) { } return *this; } /* template struct bind // rebind allocator to type U { typedef T other; }; */ template bool static_cast_assign(const X& x) { release(); if(pt_ = (T*) x) !=0) { if((pc_ = static_cast(&x)) !=0) { pc_->add_reference(); return true; } } pt_=0; return false; } template operator X* () const { X* x=0; try { x = dynamic_cast(pt_); } catch(...) { } return x; } void release() { if(pc_!=0) { pc_->release(); pt_ =0; } } bool valid() const { return pt_ !=0; } private: class impl : public rcimpl_base_signature { public: template operator X* () const { return static_cast(pt_); } impl(T* pt) : pt_(pt) {} bool valid() const { pt_ !=0; } virtual ~impl() {}; private: virtual operator void*() const { return static_cast(pt_); } T *pt_; }; void add_reference() { if(pc_!=0) pc_->add_reference(); } mutable rcimpl_base_signature* pc_; mutable T *pt_; }; /////////////////////////////////////////////////////////////////////////////////////////////////// // template > //, typename returnT=msg > class GYS_SPEC thread_safe_container : protected Container { public: thread_safe_container(const long max_sz=200) : _max_size(max_sz) {} T pop_front() //int timeout=INFINITE) { critical_section guard(get_critical_section()); if(Container::empty()) return T(); // returnT; T t(front()); Container::pop_front(); return t; } void push_back(const T& t) { if(ref_size() >0) // && t !=invalidT) { critical_section guard(get_critical_section()); correct_size(ref_size() -1); Container::push_back(t); } } critical_section_variable& get_critical_section() const { static critical_section_variable cs; return cs; } void resize(size_t n) { critical_section guard(get_critical_section()); if(n >=Container::max_size()) throw std::range_error("thread safe container :: resize. Argument too big"); correct_size(n); ref_size() = long(n); } size_t max_size() const { return ref_size(); } size_t size() const { critical_section guard(get_critical_section()); return Container::size(); } bool empty() const { critical_section guard(get_critical_section()); return Container::empty(); } // // execute 'functor' for all container // template void for_each(functor f) { critical_section guard(get_critical_section()); for(reverse_iterator it=rbegin() ; it !=rend() ; ++it) if(!f(*it)) break; } // // copy out the contents of container to the stream // std::ostream& copy_to_stream(std::ostream& s) { critical_section guard(get_critical_section()); for(reverse_iterator it=rbegin() ; it !=rend() ; ++it) s << *it; return s; } std::ostream& copy_to_stream(std::ostream& s, const T& delim) { critical_section guard(get_critical_section()); for(reverse_iterator it=rbegin() ; it !=rend() ; ++it) s << *it << delim; return s; } protected: const long _max_size; void correct_size(size_t n) { while(Container::size() >n) pop_front(); } long& ref_size() const { static long nSize = #ifdef _DEBUG 200; #else 0; #endif return nSize; } }; #pragma pack(pop, multithread_alignment_depended_part) /////////////////////////////////////////////////////////////////////////////////////////////////// // // functor to write into OutputDebugString (to work along with OutputDebugStream, TraceStream and // EventStream) // struct GYS_SPEC OutputDebug { bool operator() (const std::string& strBuf) const { return OutputDebugString(strBuf.c_str()); } bool operator() (const char* pszBuf, int k) const { return OutputDebugString(pszBuf); } static bool OutputDebugString(const char *pszBuf); static bool OutputDebugString(const std::string& strBuf); static bool& disabled(); static bool enabled() { return !disabled(); } static std::string getHtmlFormOfDisabled(std::string strName="DebugOutputDisable", std::string strInclude=""); static bool OutputDebugStringToFileLog(const char *pszBuf, int dwLen, const char* pszFileName = "c:\\temp\\gys.log"); }; /////////////////////////////////////////////////////////////////////////////////////////// // // debug, trace and event output streams. // The overhead is minimal since if debug output is disabled the stream do nothing // class GYS_SPEC OutputDebugStream : public std::basic_ostream { public: template OutputDebugStream(const T& t) : std::basic_ostream(_buf=make_buf()) { *this << t; } OutputDebugStream() : std::basic_ostream(_buf=make_buf()) {} ~OutputDebugStream() { delete _buf; } private: class GYS_SPEC buf : public std::basic_streambuf //, traits> { enum { size = 1024}; char _buffer [size]; int output_buffer(); public: buf() { setp(_buffer, _buffer + size -2); } // reserv space for /n/0 ~buf() { sync(); } // flush the buffer up virtual int_type sync() { return output_buffer(); } protected: virtual int_type overflow(int_type c = traits_type::eof()) { return output_buffer() <0 ? traits_type::eof() : traits_type::eq_int_type(c, traits_type::eof()) ? traits_type::not_eof(c) : sputc(c); } } *_buf; static buf* make_buf() { return OutputDebug::disabled()? 0:new buf; } }; class GYS_SPEC TraceStream : public std::basic_ostream { public: TraceStream(const char* p=0); ~TraceStream(); std::string str() const { return _buf==0? std::string() : _buf->str(); } // // trace history // static std::string getHtmlFormOfNumberOfTracingHistory(const std::string& strName="TracingHistory", const std::string& strInclude=""); static void put_into_history_list(const std::string& s) { get_History_container().push_back(s); } static int size_of_history_list(int n=-1); static int size_of_history_list(const std::string& sz) { return size_of_history_list(script_cast(sz)); } template static void for_each_in_history_list(functor f) { get_History_container().for_each(f); } // // // static std::ostream& copy_history_list_to_stream(std::ostream& s) { return get_History_container().copy_to_stream(s); } protected: class buf : public std::basic_stringbuf //, traits> { public: buf() : std::basic_stringbuf(std::ios_base::out) {} ~buf(); } *_buf; static buf* make_buf() { return new buf; } typedef thread_safe_container history_container; static history_container& get_History_container() { static history_container hs; return hs; } }; ////////// // // EVENTLOG_ERROR_TYPE // 1 // EVENTLOG_WARNING_TYPE // 2 // EVENTLOG_INFORMATION_TYPE // 3 // EVENTLOG_AUDIT_SUCCESS // 4 // EVENTLOG_AUDIT_FAILURE // 5 // class GYS_SPEC EventStream : public std::basic_ostream { public: EventStream(const char* name, DWORD type=EVENTLOG_ERROR_TYPE) : _buf(name, type) , std::basic_ostream(&_buf) { ; } ~EventStream() { } static const char* EventTypeName(long type, const char* const*names=0); private: class GYS_SPEC buf : public std::basic_streambuf //, traits> { public: buf(const char* name, DWORD type) : _h(::RegisterEventSource(0, name)) , _pName(name) , _type(type) { setp(_buffer, _buffer + size -1); // reserv space for /0 } ~buf() { if(_h) { sync(); ::DeregisterEventSource(_h); } } private: const char *_pName; HANDLE _h; DWORD _type; enum { size = 1024 }; char _buffer [size]; int output_buffer(); virtual int_type overflow(int_type c = traits_type::eof()) { return output_buffer() <0 ? traits_type::eof() : traits_type::eq_int_type(c, traits_type::eof()) ? traits_type::not_eof(c) : sputc(c); } virtual int_type sync() { return output_buffer(); } } _buf; }; /////////////////////////////////////////////////////////////////////////////////////////////////// // // wrapper on Win32 ::Internet(Create/Crack/Canonicalize/Combine)URL. // 1. canonicalize does not change THIS class but return result only. In case of empty string // you may want to check ::GetLastError // 2. put properties (putHostName, putUserName and so on) work properly only on URL which has // at least one valid url component // // URL url("https://www.microsoft.com:80/msdn/logon.dll?Stat?DebugDisable=checked"); // cout << boolalpha << "Setting Sheme =" << (url.Scheme = "https") // << "Setting Port =" << (url.Port = 8080) // << "Setting UserName =" << (url.UserName = "SALNIKOV") // << "Setting Password =" << (url.Password = "PASSWORD") // << "Setting HostName =" << (url.HostName = "comcast.net") // << "Setting URLPath =" << (url.UrlPath = "GeorgeSalnikov") // << "Setting ExtraInfo ="<< (url.ExtraInfo = "?data=HTML") << endl; // cout << "Result Url ="<< (std::string)url << endl; // #pragma warning(push) #pragma warning(disable : 4005) // on duplicate define #include #pragma warning(pop) class GYS_SPEC URL : public std::string { public: URL(int nSymToReserve, const char chFill='\0') { resize(nSymToReserve,chFill); } URL() {} URL(const char* o) { assign(o); } URL(const std::string& o) { assign(o); } // // with respect to STL containers (map, set, multimap, multiset need operators < and ==) // URL(const URL& o) { *this =o; } URL& operator= (const URL& o) { assign(static_cast(o)); return *this; } bool operator==(const URL& o) { return static_cast(*this) == static_cast(o); } bool operator< (const URL& o) { return static_cast(*this) < static_cast(o);} operator _bstr_t() const { return _bstr_t(c_str()); } bool crack(); // // canonicalization of this URL and some other URL string // URL& encode(DWORD flags=0) { return canonicalize(flags); } URL& decode(DWORD flags=ICU_DECODE|ICU_NO_ENCODE) { return canonicalize(flags); } URL& canonicalize(DWORD flags) { assign(canonicalize(*this, flags)); return *this; } std::string static escape(const std::string& s); std::string static unescape(const std::string& s) { return canonicalize(s, ICU_DECODE | ICU_NO_ENCODE); } std::string static encode(const std::string& s, DWORD flags=0) { return canonicalize(s, flags); } std::string static decode(const std::string& s, DWORD flags=ICU_DECODE | ICU_NO_ENCODE) { return canonicalize(s, flags); } std::string static canonicalize(const std::string& s, DWORD flags); // // combnination of this URL with some other URL. Does not encode/decode characters after "#" or "?", // and does not remove trailing white space after "?". // URL& operator+= (URL& other) { return combine(std::string(other), ICU_BROWSER_MODE); } URL& operator+= (const char* other) { return combine(std::string(other), ICU_BROWSER_MODE); } URL& operator+= (std::string& other) { return combine(other, ICU_BROWSER_MODE); } URL& combine(URL& other, DWORD dwFlags) { assign(combine(static_cast(*this), std::string(other), dwFlags)); return *this; } URL& combine(const char* other, DWORD dwFlags) { assign(combine(static_cast(*this), std::string(other), dwFlags)); return *this; } URL& combine(std::string& other, DWORD dwFlags) { assign(combine(static_cast(*this), other, dwFlags)); return *this; } std::string static combine(std::string sUrl_1, std::string sUrl_2, DWORD dwFlags) throw(CRuntime_error); // // The following are the props and their respective funcs to get/put the parts of the URL. // Domain has desirable level as arg (f.e. 2nd level of mywebpages.comcast.net returns comcast.net) // #if defined(_MSC_EXTENSIONS) __declspec(property(get=getScheme , put=putScheme )) std::string Scheme; __declspec(property(get=getHostName , put=putHostName )) std::string HostName; __declspec(property(get=getUserName , put=putUserName )) std::string UserName; __declspec(property(get=getPassword , put=putPassword )) std::string Password; __declspec(property(get=getUrlPath , put=putUrlPath )) std::string UrlPath; __declspec(property(get=getExtraInfo, put=putExtraInfo )) std::string ExtraInfo; __declspec(property(get=getPort, put=putPort )) std::string Port; __declspec(property(get=getPortNumber,put=putPortNumber )) int PortNumber; // __declspec(property(get=getDomain, )) std::string Domain[]; #endif std::string getDomain(int nLevel) { return getDomainFromHost(getHostName(), nLevel); } static std::string getDomainFromHost(const std::string& strHost, int nLevel) throw(CRuntime_error); int getPortNumber(); bool putPortNumber(int port); bool putPort(std::string o) { return putPortNumber(::atoi(o.c_str())); } std::string getPort () { return std::string(getPortNumber()==0? "" : int_to_string(_urlComponents.nPort)); } std::string getScheme () { return getString(&_urlComponents.lpszScheme, &_urlComponents.dwSchemeLength); } std::string getHostName () { return getString(&_urlComponents.lpszHostName, &_urlComponents.dwHostNameLength); } std::string getUserName () { return getString(&_urlComponents.lpszUserName, &_urlComponents.dwUserNameLength); } std::string getPassword () { return getString(&_urlComponents.lpszPassword, &_urlComponents.dwPasswordLength); } std::string getUrlPath () { return getString(&_urlComponents.lpszUrlPath, &_urlComponents.dwUrlPathLength); } std::string getExtraInfo() { return getString(&_urlComponents.lpszExtraInfo, &_urlComponents.dwExtraInfoLength); } bool putScheme (std::string o) { return putString(o, &_urlComponents.lpszScheme, &_urlComponents.dwSchemeLength); } bool putHostName (std::string o) { return putString(o, &_urlComponents.lpszHostName, &_urlComponents.dwHostNameLength); } bool putUserName (std::string o) { return putString(o, &_urlComponents.lpszUserName, &_urlComponents.dwUserNameLength); } bool putPassword (std::string o) { return putString(o, &_urlComponents.lpszPassword, &_urlComponents.dwPasswordLength); } bool putUrlPath (std::string o) { return putString(o, &_urlComponents.lpszUrlPath, &_urlComponents.dwUrlPathLength); } bool putExtraInfo(std::string o) { return putString(o, &_urlComponents.lpszExtraInfo, &_urlComponents.dwExtraInfoLength); } private: mutable URL_COMPONENTS _urlComponents; std::string getString(LPTSTR* buf, DWORD* len); bool putString(std::string s, LPTSTR* buf, DWORD* len); bool createUrl(DWORD dwSize); // void dothrow() throw(CRuntime_error) // { // throw CRuntime_error(textOfError("Source: ::InernetCrackUrl", *this), ::GetLastError()); // } }; inline URL operator+ (URL& url1, URL& url2) { URL url(url1); url +=url2; return url; } ////////////////////////////////////////////////////////////////////////////////// // // class id wrapper GUID-CLSID // class GYS_SPEC clsid : public CLSID { public: clsid() { reset(); } clsid(const CLSID& n) throw(CRuntime_error) { *this=n; } clsid(const clsid& n) { *this = n; } clsid(const char *n) { *this = n; } // n==0 -> creates new GUID clsid(std::string n) { *this = n; } bool valid() const { return _hr != CO_E_CLASSSTRING; } clsid& operator= (const clsid& n); clsid& operator= (std::string name) { return *this = name.c_str(); } clsid& operator= (const char *name); clsid& operator= (const CLSID& id) throw(CRuntime_error); bool operator==(const CLSID& other) const { return ::IsEqualGUID(*this, other) != 0; } operator HRESULT () const { return _hr; } operator std::string () const { return _sname; } clsid& create_new(); clsid& reset(); static bool valid(const std::string& n); std::ostream& getInformationOnCOMAsHtml(std::ostream& os, bool bShowInfoOnFile=true) const; protected: HRESULT _hr; std::string _sname; }; typedef clsid guid; // alias for the same structure... class GYS_SPEC progid : public CLSID { public: progid() { reset(); } progid(const CLSID& n) throw(CRuntime_error) { *this=n; } progid(const clsid& n) { *this = n; } progid(const char *n) { *this = n; } progid(const char *n1, const char* n2, ...); // multiple attempts to init progid(std::string n) { *this = n; } progid& operator= (std::string name) { return *this = name.c_str(); } progid& operator= (const progid& n); progid& operator= (const char *name) { init(name); return *this; } progid& operator= (const CLSID& id) throw(CRuntime_error); bool operator==(const CLSID& other) const { return ::IsEqualGUID(*this, other) != 0; } // operator HRESULT () const { return _hr; } operator std::string () const { return _sname; } progid& create_new(); progid& reset(); bool init(const char *name); bool valid() const { return valid(_sname); } bool registered() const { return _bRegistered; } std::ostream& getInformationOnCOMAsHtml(std::ostream& os, bool bShowInfoOnFile=true) const; static bool valid(const std::string& n); protected: std::string _sname; bool _bRegistered; }; //////////////////////////////////////////////////////////////////////////////////////////// // // some useful stuff along with to generate an HTML page which expires right away... // // See bellow global HTML& operator<<(HTML&, T& x) implementation // class GYS_SPEC HTML : public std::ostringstream { public: typedef std::pair RedirectPage; // template class Tag { std::string buff; public: const char* tag; const char* text; Tag(const char* tagname, const char* value) : tag(tagname) , text(value) {} Tag(const char* tagname, std::string& value) : tag(tagname) , buff(value) , text(buff.c_str()) {} Tag(const char* tagname, int value) : tag(tagname) , buff(int_to_string(value)) , text(buff.c_str()) {} Tag(const char* tagname, const std::exception& value) : tag(tagname) , text(buff.c_str()) {} // ?? Tag(const char* tagname, const CRuntime_error& value) : tag(tagname) , buff((std::string)value) , text(buff.c_str()) {} // ?? Tag(const char* tagname, Tag& value) : tag(tagname) , buff((std::string)value) , text(buff.c_str()) {} // ?? operator std::string () { if(tag==0) return buff; buff = std::string("<") + tag + std::string(">") + text + std::string(""); tag =0; text = buff.c_str(); return buff; } }; struct ModalErrorDialog { const std::exception& error; std::string title; std::string suffix; std::string action; ModalErrorDialog(const std::exception& err, std::string t=std::string(), std::string sfx=std::string(), std::string act=std::string()) : error(err), title(t) , suffix(sfx) , action(act) { } }; // // constructors // HTML() {} HTML(std::string title, const std::string style=HTML::strSTYLE(), const std::string script=HTML::strSCRIPT()) : _strTitle(title) { Init(style, script); } HTML(const char* title, const std::string style=HTML::strSTYLE(), const std::string script=HTML::strSCRIPT()) : _strTitle(title?title:"") { Init(style, script); } HTML(const ModalErrorDialog& err) { insert(err); } // // extensions to inserters (general and specific ones) // templateHTML& insert(const T& t) { static_cast(*this) << t; return *this; } template<>HTML& insert(text_files_cache& x); // template<>HTML& insert(text_file& x); template<>HTML& insert(FileVersion& x); template<>HTML& insert(FileInformation& x); template<>HTML& insert(CStatistics& x); template<>HTML& insert(HTTP_POST_data& x); template<>HTML& insert(HTTP_query_string& x); template<>HTML& insert(HTTP_cookie& x); template<>HTML& insert(const std::exception& e) { static_cast(*this)<HTML& insert(const CRuntime_error& e) { static_cast(*this)<<(std::string) e; return *this; } template<>HTML& insert(const Tag& t) { static_cast(*this) << "<" << t.tag << ">" << t.text << ""; return *this; } template<> HTML& insert(const RedirectPage& url) { *this << "\r\n\r\n"; return *this; } template<> HTML& insert(const ModalErrorDialog& err) { *this << "" << (err.action.empty()? "" : " ") << "" ""; return *this; } // // accessors // operator std::string() { return static_cast(*this).str(); } operator const char*() { return static_cast(*this).str().c_str(); } // // closes BODY and HTML if they are not there // std::string str(); // // convert 'this' content into invisile SPAN with 'id'; the content will popup in modal HTML browser // std::string makeModalDialogSPAN(std::string id="_id_popup_"); protected: std::string _strTitle; void Init(const std::string& style, const std::string& script); public: static std::string strRedirect(URL& url); static std::string strHTMLBegin(); static std::string strHTMLEnd(); static std::string strHTMLPasswordSubmitButtons(std::string name ="Password"); static HTML& FloatingAdvertisement(HTML& s, const char* content, const char* title="?"); static std::string strAHREF(const std::string& href, const std::string& label=std::string()); static const std::string& strSTYLE(); static const std::string& strSCRIPT(); std::string static escape(const std::string& s); std::string static unescape(const std::string& s) { return URL::canonicalize(s, ICU_DECODE | ICU_NO_ENCODE); } }; /* TODO: incorporate HTML resource access into HTML class ///////////////////////////////////////////////////////////////////////////////////////// // // access to Html resources in C++ projects // // class GYS_SPEC CHtmlResource { LPVOID m_pBuf; DWORD m_dwLen; std::string m_strResourceID; void Init(const char* pszResourceID); public: explicit CHtmlResource(UINT nID); explicit CHtmlResource(const char* pszResourceID); CHttpServerContext& operator>> (CHttpServerContext& ctxt); operator CString () { return CString((LPCTSTR)m_pBuf, m_dwLen); } operator std::string() { return std::string((LPCTSTR)m_pBuf, m_dwLen); } // // with respect to std::map... (can I rely on default copy constructor?) // CHtmlResource(const CHtmlResource& other) { *this = other; } CHtmlResource& operator= (const CHtmlResource& other); ~CHtmlResource(); }; inline CHttpServerContext& operator<< (CHttpServerContext& ctxt, CHtmlResource& rc) { return rc >> ctxt; } ///////////////////////////////////////////////////////////////////////////////////////// // // CHtmlResource is a helper to get HTML text from resources (see CContentsExtension::TopFrame) // CHtmlResource& CHtmlResource::operator= (const CHtmlResource& other) { m_pBuf = other.m_pBuf; m_dwLen = other.m_dwLen; return *this; } CHttpServerContext& CHtmlResource::operator>> (CHttpServerContext& ctxt) { // // write whole bulk of HTML code at once to avoid moving data in memory // if(ctxt.m_pStream != 0) if(m_dwLen != 0 && m_dwLen != 0xFFFFFFFF) ctxt.m_pStream->Write(m_pBuf, m_dwLen); else throw CRuntime_error("Source: CHtmlResource Utility, (m_strResourceID + " resource does not exist").c_str()); return ctxt; } CHtmlResource::CHtmlResource(UINT nID) : m_pBuf(0) , m_dwLen(0) { std::ostringstream stream; // to use stream's conversion capabilities stream << "#" << nID; Init(stream.str().c_str()); } CHtmlResource::CHtmlResource(const char *pszResourceID) : m_pBuf(0) , m_dwLen(0) { Init(pszResourceID); } #if !(defined _DEBUG) #error kill this line on release version void CHtmlResource::Init(const char *pszResourceID) { typedef std::map THtmlResourceContainer; static THtmlResourceContainer m_mapOpened; // delete m_pBuf; m_pBuf = 0; m_dwLen = 0; m_strResourceID = pszResourceID; THtmlResourceContainer::iterator iter = m_mapOpened.find(m_strResourceID); if(iter != m_mapOpened.end()) { *this = iter->second; return; } HRSRC hres = ::FindResource(::AfxGetInstanceHandle(), m_strResourceID.c_str(), RT_HTML); if(hres != NULL) { m_dwLen = ::SizeofResource(::AfxGetInstanceHandle(), hres); HGLOBAL m_hgRes = ::LoadResource(::AfxGetInstanceHandle(), hres); m_pBuf = ::LockResource(m_hgRes); } m_mapOpened.insert(THtmlResourceContainer::value_type(m_strResourceID, *this)); } CHtmlResource::~CHtmlResource() { } #else void CHtmlResource::Init(const char *pszResourceID) { delete m_pBuf; m_pBuf = 0; m_dwLen = 0; m_strResourceID = pszResourceID; static struct { const char *pszResourceID; const char *pszFileName; } files [] = { "FrameOfMainMenu", "HTML\\FrameOfMainMenu.htm", "FrameOfAccelerators", "HTML\\FrameOfAccelerators.htm", "XSLTWBMenuCOMobjectMenu", "HTML\\XSLT-WBMenu-COM-object-Menu.xslt", "XSLTWBMenuCOMobjectAccelerators", "HTML\\XSLT-WBMenu-COM-object-Accelerators.xslt", "#122", "HTML\\sessionId.htm", // IDR_SESSION_ID "", NULL, }; for(int i = 0 ; m_strResourceID != files[i].pszResourceID ; ++i) { if(files[i].pszResourceID[0] == 0) return; } char strPath[500], *pstrFilePart; ::GetFullPathName(__FILE__, sizeof(strPath) -60, strPath, &pstrFilePart); lstrcpy(pstrFilePart, files[i].pszFileName); HANDLE hFile = ::CreateFile(strPath,GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES)NULL,OPEN_EXISTING,FILE_ATTRIBUTE_READONLY,(HANDLE)NULL); if(hFile == INVALID_HANDLE_VALUE) { DWORD err = ::GetLastError(); m_pBuf = new char[600]; sprintf((char*)m_pBuf, "0x%d on openninig local resource file %s",err,strPath); throw _bstr_t((char*)m_pBuf); return; } if((m_dwLen = ::GetFileSize(hFile,NULL)) != 0xFFFFFFFF) { m_pBuf = new char[m_dwLen]; DWORD dwRead; ::ReadFile(hFile, m_pBuf, m_dwLen, &dwRead, NULL); } ::CloseHandle(hFile); } CHtmlResource::~CHtmlResource() { delete [] m_pBuf; } #endif */ //////////////////////////////////////////////////////////////////////////////////////// // // a time to represent statistics // class GYS_SPEC statistics_time { public: statistics_time() : _changed_on(0) {} statistics_time(const statistics_time& other) : _changed_on(other._changed_on) {} statistics_time& operator= (const statistics_time& other) { _changed_on =other._changed_on; return *this; } void reset() { _changed_on =0; } time_t changed_on () const { return _changed_on; } virtual time_t fix_changed_on_time() { return ::time(&_changed_on); } bool is_valid() const { return _changed_on !=0; } bool is_invalid() const { return _changed_on ==0; } protected: time_t _changed_on; }; //////////////////////////////////////////////////////////////////////////////////////// // // a statistics of general type T. Offers the operations of minimum, maximum, greater // or equal, less or equal, increment, decrement, addition, subtraction to/from // T value it keeps along with time fixation of those changes. NOTE: this template // is not thread safe (see CStatistics below that implements threadsafety) // template class statistics : public statistics_time { public: statistics() { reset();} statistics(const T& t) { *this = t; } // // in respect to STL containers we gotta define the next two // statistics(const statistics& other) { *this = other; } statistics& operator= (const statistics& other) { _changed_on = other._changed_on; _value = other._value; return *this; } bool operator== (const statistics& other) const { return _changed_on == other._changed_on && _value == other._value; } bool operator!= (const statistics& other) const { return !(*this ==other); } // // the next /increment/decrement/reset and set statistics depending on argument // statistics& reset() { _value =init_value; statistics_time::reset(); return *this;} statistics& operator= (const T& t) { _value = t; fix_changed_on_time(); return *this; } statistics& operator++() { ++_value; fix_changed_on_time(); return *this; } statistics& operator--() { --_value; fix_changed_on_time(); return *this; } statistics& operator+=(const T& t) { _value+=t; fix_changed_on_time(); return *this; } statistics& operator-=(const T& t) { _value-=t; fix_changed_on_time(); return *this; } statistics& add (const T& t) { _value +=t; fix_changed_on_time(); return *this; } statistics& assign (const T& t) { _value = t; fix_changed_on_time(); return *this; } statistics& greater_equal(const T& t) { if(is_invalid() || t >=_value) return *this=t; return invalid_statistics(); } statistics& less_equal (const T& t) { if(is_invalid() || t <=_value) return *this=t; return invalid_statistics(); } statistics& maximum (const T& t) { if(is_invalid() || t > _value) return *this=t; return invalid_statistics(); } statistics& minimum (const T& t) { if(is_invalid() || t < _value) return *this=t; return invalid_statistics(); } operator T() const { return _value; } private: T _value; inline static statistics& invalid_statistics(); }; // // const statistics which is always invalid // template class statistics_invalid : public statistics { public: statistics_invalid() {} virtual time_t fix_changed_on_time() { time_t r; return _changed_on =0; return ::time(&r); } statistics& get_statistics() { return static_cast& >(*this); } }; template inline statistics& statistics::invalid_statistics() { static statistics_invalid r; return r.get_statistics(); } //////////////////////////////////////////////////////////////////////////////////////// // // thread safe map repository of statistics of 'long's. Use opeartor[key] to get // access to value itself; for NOT atomic operations use GeneralCriticalSection: // // ..... // { // CStatistics stat; // GeneralCriticalSection(); // long ok=stat["OK"]; // stat["OK"] = ok >=24? 0: ok+1; // } // class GYS_SPEC CStatistics { public: CStatistics();// : _disabled(false) { ::time(&_start_time); } // disable(0); } typedef statistics long_statistics; typedef statistics_invalid long_statistics_invalid; typedef std::map TMap; std::string getHtmlFormOfDisabled(std::string strName="StatDisable", std::string strInclude=""); std::string getHtmlFormOfResetAll(std::string strName="StatResetAll", std::string strInclude=""); TMap& getRawMap() { return _map; } // // write-read access to statistics // // disable accesses to internal variable also (1 - disabled, 0 - enabled, -1 -- check the state) // long disable(long d=-1); long_statistics assign(const char *key, long value=0); void minmax(std::string key, long value); // // sets key+last_fixed, key+minimum, key+maximum, key+integral, key+average, key+number_of_occurences // void full(const std::string& key, long value); // // counts +-value of key+last_fixed_value, and key+maximum_value. Cannot go down of zerro // void count(const std::string& key, long value); long_statistics greater_equal(const char *key, long value); long_statistics less_or_equal(const char *key, long value); long_statistics maximum(const char *key, long value); long_statistics minimum(const char *key, long value); long_statistics increment(const char *key); long_statistics decrement(const char *key); // // read-only acccess to statistics // void reset(); long_statistics reset(const char *key); long_statistics operator[](const char *key); // // stream/string outputs // std::ostream& getStatistics(std::ostream&os, const char*pszBOL,const char*pszDelim1, const char*pszDelim2, const char*pszEOL); std::ostream& getTimeInformation(std::ostream& os, const char* pszBOL="", const char* pszDelim=": ", const char* pszEOL="\n\r"); std::ostream& getStatisticsAsHtml(std::ostream& os); std::ostream& getStatisticsAsPartOfHtmlTable(std::ostream& os); HTML& getStatistics(HTML& os) { getStatisticsAsHtml(static_cast(os)); return os; } std::ostream& getStatistics(std::ostream& os); std::string getStatistics(const char*pszBOL="",const char*pszDelim1="=",const char*pszDelim2=", time=",const char*pszEOL="\n\r"); std::string getTimeInformation(const char* pszBOL="", const char* pszDelim=": ", const char* pszEOL="\n\r"); std::string getStatisticsAsHtml(); static std::string time_to_string(time_t t, const char* pszFormat="%#c"); protected: TMap _map; bool _disabled; critical_section_variable _cs; CStatistics(const CStatistics&){} CStatistics& operator=(const CStatistics&){ return *this; } time_t _start_time; }; /////////////////////////////////////////////////////////////////////////////// // // a templated and reference counted window handle. Automaticaly closes object when // all the handles goes out of scope. This class is designed for only deriviation // there is no way to know how handle has to be created // template //, BOOL (*pFuncToClose)()=::CloseHandle> class handle { public: handle() : _h(hInvalid) {;} // Default constructor assumes an invalid value (nothing to cleanup) handle(H h) : _h(h) {;} virtual ~handle() { close(); } handle& operator=(H h) { setHandle(h); return *this; } bool valid() const { return _h != hInvalid; } operator H() const { return _h; } H getHandle() const { return _h; } // // some handles need different close functions (CloseRegHandle) // virtual bool close() { bool bRet = valid() ? ::CloseHandle(_h) != FALSE : true; // bool bRet = valid() ? pFuncToClose(_h) != FALSE : true; _h = hInvalid; return bRet; } protected: void setHandle(H h) { close(); _h = h; } private: H _h; }; template class WinHandle { public: WinHandle() : _h(hInitial) {;} // Default constructor assumes an invalid value (nothing to cleanup) WinHandle(H h) : _h(h) {;} virtual ~WinHandle() { close(); } WinHandle& operator=(H h) { setHandle(h); return *this; } bool valid() const { return _h != hInvalid && _h != hInitial; } operator H() const { return _h; } H getHandle() const { return _h; } // // some handles need different close functions (CloseRegHandle) // virtual bool close() { bool bRet = valid() ? FunctorCloser(_h) != 0 : true; _h = hInitial; return bRet; } protected: void setHandle(H h) { close(); _h = h; } private: H _h; }; ////////////////////////////////////////////////////////////////////////////////////////// // // a simple semaphore // class GYS_SPEC semaphore : public handle { public: semaphore(int max_num) { setHandle(::CreateSemaphore( NULL, // security 0, // initial pool count max_num, 0)); // no named kernel object } bool release() { return valid()? false : ::ReleaseSemaphore(getHandle(), 1, NULL) != FALSE; } bool wait(DWORD timeout=INFINITE) { return valid()? false : ::WaitForSingleObject(getHandle(), timeout) != WAIT_OBJECT_0; } private: virtual bool close() { HANDLE h = getHandle(); if(h == 0) return true; bool b = ::CloseHandle(h) != FALSE; h=0; return b; } }; ///////////////////////////////////////////////////////////////////////////// // // RegistryKey represents a registry key. // // by exporting DllRegisterServer (DllUnregisterServer), you can use regsvr.exe (-u) // // STDAPI DllRegisterServer(void) // { // RegistryKey reg; // bool // bRes = reg.Open(HKEY_CLASSES_ROOT, "SomeCo.SomeObjectID"); // bRes &= reg.SetValue("", "Some Company Some ObjectID"); // bRes &= reg.Open(HKEY_CLASSES_ROOT, "SomeCo.SomeObjectID\\CLSID"); // bRes &= reg.SetValue("", "{1BF64B56-9684-11D2-9AA9-0000F870EE1D}"); // bRes &= reg.Open(HKEY_CLASSES_ROOT, "CLSID\\{1BF64B56-9684-11D2-9AA9-0000F870EE1D}"); // bRes &= reg.SetValue("", "Some Company Some ObjectID"); // // // the full path to this dll // char szFileName[1000]; szFileName [0]=0; // ::GetModuleFileName(WFolderDLLDLL.hModule, szFileName, sizeof(szFileName) -1); // // bRes &= reg.Open(HKEY_CLASSES_ROOT, "CLSID\\{1BF64B56-9684-11D2-9AA9-0000F870EE1D}\\InProcServer32"); // bRes &= reg.SetValue("", szFileName); // bRes &= reg.SetValue("ThreadingModel", "Apartment"); // bRes &= reg.Open(HKEY_CLASSES_ROOT, "CLSID\\{1BF64B56-9684-11D2-9AA9-0000F870EE1D}\\ProgID"); // bRes &= reg.SetValue("", "SomeCo.SomeObjectID"); // return bRes? S_OK : ResultFromScode(SELFREG_E_CLASS); // } // // STDAPI DllUnregisterServer(void) // { // RegistryKey reg; // bool // bRes = reg.Open(HKEY_CLASSES_ROOT, "SomeCo.SomeObjectID"); // bRes &= reg.Delete(); // bRes &= reg.Open(HKEY_CLASSES_ROOT, "CLSID\\{1BF64B56-9684-11D2-9AA9-0000F870EE1D}"); // bRes &= reg.Delete(); // return bRes? S_OK : ResultFromScode(SELFREG_E_CLASS); // } // class GYS_SPEC RegistryKey { public: // constructor/destructor stuff ~RegistryKey() { Close(); } RegistryKey() { Init(); } RegistryKey(const RegistryKey& copy, const char *szSubFolderName=NULL, REGSAM sAccess = KEY_ALL_ACCESS, DWORD option = REG_OPTION_NON_VOLATILE, LPSECURITY_ATTRIBUTES psSecur = NULL); RegistryKey(HKEY hParentKey, const char *szSubFolderName, REGSAM sAccess = KEY_ALL_ACCESS, DWORD option = REG_OPTION_NON_VOLATILE, LPSECURITY_ATTRIBUTES psSecur = NULL); // opens new key or subkey in m_hKey bool Open(HKEY hParentKey, const char *szSubFolderName, REGSAM sAccess = KEY_ALL_ACCESS, DWORD dwOption = REG_OPTION_NON_VOLATILE, LPSECURITY_ATTRIBUTES psSecur = NULL); void Close(); RegistryKey& operator= (const RegistryKey& from); bool Delete(); // deletes this key and all the data it contens bool DeleteAllValues(); // deletes all the values or this key bool DeleteAllKeys(); // deletes the subkey(s) (including underlaying data) bool Valid() const { return m_hKey !=0; } // // get/set/delete value suit // bool SetValue(const char* szValName, int iValue); bool SetValue(const char* szValName, const char* pValue); bool SetValue(const char* szValName, const BYTE* pValue, int iValueLen, DWORD dwValType = REG_BINARY); // // // class Value { public: Value() : type_(REG_NONE) {} Value(DWORD tp, const std::vector& buf, int len=-1); Value(const Value& x) { *this =x; } Value& operator=(const Value& x); operator void* () { return type_ ==REG_NONE? 0: this; } operator bool () const { return type_ !=REG_NONE; } operator std::string () const { std::ostringstream os; output(os); return os.str(); } operator DWORD() const; std::ostream& output(std::ostream& os) const { return output(os, type_, &value[0], value.size()); } static std::ostream& output(std::ostream& os, DWORD dwType, const unsigned char* bVal, int lenVal); template std::ostream& output(std::ostream& os, TrObject transformer) const { if(value.size()==0) return os; switch(type_) { case REG_EXPAND_SZ: { std::vector val(::ExpandEnvironmentStrings((const char*)&value[0], 0, 0)); ::ExpandEnvironmentStrings((const char*)&value[0], &val[0], val.size()); os << transformer(&val[0]); } break; case REG_SZ: os << transformer(std::string((char*)&value[0])); break; // case REG_MULTI_SZ: // An array of null-terminated strings, terminated by two null characters. default: return output(os, type_, &value[0], value.size()); break; } return os; } DWORD type() const { return type_; } int length() const { return value.size(); } operator const unsigned char* () const { return &value[0]; } operator const char* () const { return (const char*)&value[0]; } Value& clear() { type_ = REG_NONE; value.clear(); return *this; } // // inserter // template friend std::basic_ostream& operator<< (std::basic_ostream& os, const Value& v) { return output(os); } private: friend class RegistryKey; DWORD type_; typedef std::vector value_t; value_t value; }; Value GetValue(const char* szValName) const { Value val; GetValue(szValName, val); return val; } bool GetValue(const char* szValName, Value& val) const; std::string GetStringValue(const char* szValName) const { return (std::string) GetValue(szValName); } DWORD GetDWORDValue(const char* szValName) const; // // helper to read a value at once // static std::string GetStringValue(HKEY hParentKey, const std::string& strSubFolderName, const char *szValName=""); typedef std::map Values; void EnumerateValues(Values& m) const { if(m_hKey ==0) return; std::vector sName(iMaxValueNameLen+MAX_PATH); std::vector bVal(iMaxValueLen+MAX_PATH); for(DWORD dwIndex=0 ; dwIndex < iValues ; ++dwIndex) { DWORD lenName = sName.size(); // size of value name buffer DWORD lenVal = bVal.size(); // size of value name buffer DWORD dwType = REG_NONE; if(ERROR_SUCCESS !=::RegEnumValue(m_hKey, dwIndex, &sName[0], &lenName, 0, &dwType, &bVal[0], &lenVal)) continue; m.insert(std::pair(std::string(&sName[0], lenName), Value(dwType, bVal, lenVal))); } } std::ostream& EnumerateValues(std::ostream& os, const char* bol, const char *del, const char* eol) const { Values v; EnumerateValues(v); for(Values::const_iterator it = v.begin() ; it != v.end() ; ++it) { os << bol << it->first << del ; it->second.output(os) << eol; } return os; } std::ostream& EnumerateValuesAsHtmlTBODY(std::ostream& os)const //, TrObject transformer) const { Values v; EnumerateValues(v); for(Values::const_iterator it = v.begin() ; it != v.end() ; ++it) { os << "3 " << it->first << ""; it->second.output(os, HTML::escape) << ""; } return os; } std::string LastError() const { return textOfError("Registry operation", m_err); } void EnumerateKeys(std::vector& subkeys) const; std::ostream& getInformationAsHtml(std::ostream& os, const char* pszNamePrefix="") const; private: DWORD iNumSubKeys; // number of subkeys DWORD iMaxSubKeyLen; // longest subkey name DWORD iMaxClassLen; // longest class string DWORD iValues; // number of value entries DWORD iMaxValueNameLen; // longest value name DWORD iMaxValueLen; // longest value data DWORD iSecurityDescriptor; // descriptor length FILETIME LastWriteTime; // last write time void Init(); void Init(const char *szSubFolderName, DWORD dwOption, REGSAM sAccess, LPSECURITY_ATTRIBUTES psSecur); DWORD m_err; unsigned long m_dwDisp; mutable HKEY m_hKey; HKEY m_hParentKey; std::string m_strSubFolderName; REGSAM m_sAccess; DWORD m_dwOption; LPSECURITY_ATTRIBUTES m_psSecur; }; ///////////////////////////////////////////////////////////////////////////////////////// // // Information on THIS computer // class GYS_SPEC ThisComputer { public: static std::ostream& Information(std::ostream& s); // full info on comp static std::ostream& MisceleniousInfo (std::ostream& s, const char*bol="", const char*dm1=": ", const char*dm2=". ", const char*eol="\r\n") throw(CRuntime_error); static std::ostream& OSInfo (std::ostream& s, const char*bol="", const char*dm1=": ", const char*dm2=". ", const char*eol="\r\n"); static std::ostream& CPUFromRegistryInfo(std::ostream& s, const char*bol="", const char*dm1=": ", const char*dm2=". ", const char*eol="\r\n", const char* separator="\r\n"); static std::ostream& CPUInfo (std::ostream& s, const char*bol="", const char*dm1=": ", const char*dm2=". ", const char*eol="\r\n"); static std::ostream& MemoryInfo (std::ostream& s, const char*bol="", const char*dm1=": ", const char*dm2=". ", const char*eol="\r\n"); static std::ostream& print_size (std::ostream& s, DWORD l, DWORD h=0); static std::ostream& print_size (std::ostream& s, ULARGE_INTEGER& uli) { return print_size(s, uli.LowPart, uli.HighPart); } static std::ostream& VolumesInfo (std::ostream& s, const char*bol="", const char*dm1=": ", const char*dm2=". ", const char*eol="\r\n", const char* separator="\r\n", const char* yes="yes", const char* no="no"); static bool VolumeInfo (std::ostream& s, const char sC[], const char*bol="", const char*dm1=": ", const char*dm2=". ", const char*eol="\r\n", const char* yes="yes", const char* no="no"); static std::ostream& NetworkInfo (std::ostream& s, const char*bol="", const char*dm1=": ", const char*dm2=". ", const char*eol="\r\n", const char* separator="\r\n") throw(CRuntime_error); #ifdef _PSAPI_H_ // PSAPI is not a part of WINDOWS but a SDK dll static std::ostream& ProcessInfo(std::ostream& s, DWORD id, const char* bol="", const char *dl1=": ", const char *dl2=". ", const char *eol="\r\n"); static std::ostream& ProcessesInfo(std::ostream& s, const char*bol="", const char*dm1=": ", const char*dm2=". ", const char*eol="\r\n", const char* separator="\r\n"); #endif }; ///////////////////////////////////////////////////////////////////////////////////////// // // typedef struct _WIN32_FIND_DATA { typedef struct _BY_HANDLE_FILE_INFORMATION { // DWORD dwFileAttributes; DWORD dwFileAttributes; // FILETIME ftCreationTime; FILETIME ftCreationTime; // FILETIME ftLastAccessTime; FILETIME ftLastAccessTime; // FILETIME ftLastWriteTime; FILETIME ftLastWriteTime; // DWORD nFileSizeHigh; DWORD dwVolumeSerialNumber; // DWORD nFileSizeLow; DWORD nFileSizeHigh; // DWORD dwReserved0; DWORD nFileSizeLow; // DWORD dwReserved1; DWORD nNumberOfLinks; // char cFileName[ MAX_PATH ]; DWORD nFileIndexHigh; // char cAlternateFileName[ 14 ]; DWORD nFileIndexLow; // } WIN32_FIND_DATA; } BY_HANDLE_FILE_INFORMATION; // typedef WIN32_FIND_DATA FILE_INFORMATION_STRUCTURE; class GYS_SPEC FileInformation : public STL_adapter { public: FileInformation() {} FileInformation(const FileInformation& x) { *this = x; } FileInformation(const std::string& strFilename) { init(strFilename.c_str()); } FileInformation(const char *pszFilename) { init(pszFilename); } FileInformation(HMODULE hFile) { init(hFile); } ~FileInformation() {} FileInformation& operator=(const FileInformation& x) { assign(x); return *this; } bool exist() const { static const STL_adapter x; return *this !=x; } // x is an empty structure! std::string getFileName() const { return cFileName; } // // if init returns false, ::GetLastError() has an explanation // bool init(HMODULE hFile); bool init(const char *pszFilename); std::string attribute(DWORD a){ return std::string((dwFileAttributes&a)!=0? "v":" "); }; // // stream/string output // std::ostream& getFileInformationAsHtml(std::ostream& os); std::ostream& getFileInformation(std::ostream& os); HTML& getFileInformation(HTML& os) { getFileInformationAsHtml(os); return os; } std::string getFileInformationAsHtml() { HTML s; return (std::string) getFileInformation(s); } }; ///////////////////////////////////////////////////////////////////////////////////////// // // wrapper on // struct VS_FIXEDFILEINFO { // DWORD dwSignature; // DWORD dwStrucVersion; // DWORD dwFileVersionMS; // DWORD dwFileVersionLS; // DWORD dwProductVersionMS; // DWORD dwProductVersionLS; // DWORD dwFileFlagsMask; // DWORD dwFileFlags; // DWORD dwFileOS; // DWORD dwFileType; // DWORD dwFileSubtype; // DWORD dwFileDateMS; // DWORD dwFileDateLS; // }; // class GYS_SPEC FileVersion : public STL_adapter { public: FileVersion() : m_pVersionInfo(0){ } FileVersion(HMODULE h) : m_pVersionInfo(0) { init(h); } FileVersion(const std::string& fileName) : m_pVersionInfo(0) { init(fileName.c_str()); } FileVersion(const char* fileName) : m_pVersionInfo(0) { init(fileName); } virtual ~FileVersion() { delete [] m_pVersionInfo; } std::string getFileName() { return m_strFileName; } bool init(HMODULE lib); bool init(const char* modulename); bool valid() const { return m_pVersionInfo !=0; } // && dwSignature == VS_FFI_SIGNATURE; } std::string value(const char* lpKeyName) const; std::string getValueAsHtml(const char* lpKeyName) const; std::string getCreatedTimeAsHtml() const; std::string getCreatedTimeAsString() const; std::string getFlagsInfoAsHtml() const; std::ostream& getFlagsInfoAsHtml(std::ostream& s) const; std::ostream& getFileVersionAsHtml(std::ostream& os) const; // stream/string output std::ostream& getFileVersion(std::ostream& os) const; HTML& getFileVersion(HTML& os) const { getFileVersionAsHtml(os); return os; } std::string getFileVersionAsHtml() const { HTML s; return (std::string) getFileVersion(s); } protected: BYTE* m_pVersionInfo; // all version info struct TRANSLATION { WORD langID; // language ID WORD charset; // character set (code page) } m_translation; std::string m_strFileName; // full file name }; ////////////////////////////////////////////////////////////////////////////////////////////// // class GYS_SPEC InternetExplorer { public: static std::string PathToExecutable(); static std::ostream& getFullInformationAsHtml(std::ostream& os); static HINSTANCE ShellExecute(const URL& url=URL()); static void Open(const URL& url=URL())throw(CRuntime_error); }; ////////////////////////////////////////////////////////////////////////////////////////////// // // thread safe read-in cache of files' contents and these files' informations. // NOTE: file size should be fairly small, since chunk by chunk reading is not implemented // file name is case insensitive // TODO: implement read-out data chunk by chunk and pending input // class GYS_SPEC text_files_cache { public: text_files_cache() {} ~text_files_cache() {} void clear(); std::string get_contents(const std::string& filename); FileInformation get_information(const std::string& filename); HTML& getFileInformation(HTML& os, std::string filename=std::string()); static std::string getHtmlFormClearCache(std::string strName="ClearFileCache", std::string strInclude=""); private: typedef std::map TmapTextFilesInformation; typedef std::map TmapTextFiles; TmapTextFiles s_mapTextFiles; TmapTextFilesInformation s_mapTextFilesInformation; critical_section_variable s_csTextFiles; }; /////////////////////////////////////////////////////////////////////////////////////////////////// // // class functor to read-cache-in text files (file size should be fairly small). Thread safe // class GYS_SPEC text_file : public std::string { public: text_file() {} text_file(const char *filename) { *this =filename; } text_file(const std::string& filename) { *this =filename; } text_file(const text_file& filename) { *this =filename; } text_file& operator= (const char *filename) { *this = std::string(filename); return *this; } text_file& operator= (const std::string& filename) { assign(text(filename)); return *this; } text_file& operator= (const text_file& x) { assign(static_cast(x)); return *this; } text_file& replace(const std::string& f, const std::string& r, int n=1); text_file& replace_or_append(const std::string& f, const std::string& r); text_file& insert(const std::string& f, const std::string& r, int n=1); // // static cache. returns COPY of the string-contents of file (thread-safe) // static text_files_cache& get_cache(); static std::string text(const std::string& filename) throw(CRuntime_error); static HTML& information(HTML& os, const std::string& filename=std::string()) throw(CRuntime_error); }; ///////////////////////////////////////////////////////////////////////////////////////// // // Comma-separted-values parser class // // parse first iNumStrings of user info received from a mainframe into the vector; default delimiter // is a backslash \ // // class GYS_SPEC CSV_parser : public std::vector // list { public: typedef std::vector string_vector; CSV_parser(char chDel=',') : pszDelim(chDel) , _parsed(0) {}; CSV_parser(unsigned maxsize, char chDel=',') : pszDelim(chDel) , _parsed(0) { set_max_size(maxsize); }; CSV_parser(const std::string& str, unsigned maxsize, char chDel=',') : pszDelim(chDel) , _parsed(0) { set_max_size(maxsize); add(str); } CSV_parser(const char *p, unsigned maxsize, char chDel=',') : pszDelim(chDel) , _parsed(0) { set_max_size(maxsize); add(p); }; virtual ~CSV_parser() {} int parsed() const { return _parsed; } size_t max_size() const { return _max_size; } CSV_parser& set_max_size(size_t m) throw(CRuntime_error); CSV_parser& operator =(const char *p) { return assign(p); } CSV_parser& operator +=(const char *p) { return add(p); } CSV_parser& operator =(const std::string& s) { return assign(s); } CSV_parser& operator +=(const std::string& s) { return add(s); } CSV_parser& assign (const char *p) { empty(); _parsed=0; return add(p); } CSV_parser& add (const char *p) { if(p !=0)add(std::string(p)); return *this; } CSV_parser& assign (const std::string& str) { empty(); _parsed=0; return add(str);} CSV_parser& add (const std::string& str); operator std::string () const { return getAsString(); } // returns *this* content as a string std::string getAsString(unsigned beg=0, unsigned end=-1) const; // // additional safe access to vector // std::string value_of(unsigned i) const { return i < size()? at(i) : std::string(); } bool exists(unsigned i) const { return i < size(); } protected: int _parsed; unsigned _max_size; char pszDelim; }; ///////////////////////////////////////////////////////////////////////////////////////// // // Comma-separted-values format template class, a flavor of CSV_parser // template struct CSV : public CSV_parser { CSV() : CSV_parser(pszDelim) {} CSV(unsigned maxsize) : CSV_parser(maxsize, chDelim) {} CSV(const std::string& str, unsigned maxsize) : CSV_parser(str, maxsize, chDelim) {} CSV(const char *p, unsigned maxsize) : CSV_parser(p, maxsize, chDelim) {} }; ///////////////////////////////////////////////////////////////////////////////////////// // //std::string Do_Nothing_String_Tranformer(std::string& s) { return s; } ///////////////////////////////////////////////////////////////////////////////////////// // // string pair parser helps parse a string into a Container. Ignores empty key lines. // Container should be STL complaint one that implements 'insert' method (map, multimap, // set, multiset, dequeue, vector, stack, list, priority_queue, queue) // template > //, std::less<_chSeparator> > > class string_pair_parser : public Container { public: typedef Container::iterator iterator; typedef Container::const_iterator const_iterator; typedef Container::reverse_iterator reverse_iterator; typedef Container::const_reverse_iterator const_reverse_iterator; virtual ~string_pair_parser() {} string_pair_parser() {} string_pair_parser(const std::string& x) { add(x); } string_pair_parser(const char *x) { add(x); } string_pair_parser(const string_pair_parser& x) { add(x); } string_pair_parser& operator+= (const string_pair_parser& x){ return add(x); } string_pair_parser& operator+= (const char* x) { return add(x); } string_pair_parser& operator+= (const std::string& x) { return add(x); } string_pair_parser& operator= (const string_pair_parser& x) { return assign(x); } string_pair_parser& operator= (const char* x) { return assign(x); } string_pair_parser& operator= (const std::string& x) { return assign(x); } // // // string_pair_parser& assign (const string_pair_parser& x) { clear(); return add(x); } string_pair_parser& assign (const std::string& x) { clear(); return add(x); } string_pair_parser& assign (const char* x) { clear(); return add(x); } template string_pair_parser& assign_with_transformation(const std::string& x, TransformObject Transformer) { clear(); return parse_string_with_transformation(x, Transformer); } string_pair_parser& add(const char* x) { if(x!=0) add(std::string(x)); return *this; } string_pair_parser& add(const std::string& x) { return parse_string_with_transformation(x, do_nothing()); } template string_pair_parser& parse_string_with_transformation(const std::string& x, TransformObject Transformer) { for(std::istringstream sX(x) ; !sX.eof() ; ) { std::string strBuf; std::getline(sX, strBuf, _chSeparator); // cookies are separated by semicolon ; int nEqu; if(trim(strBuf).empty() || (nEqu=strBuf.find(_chDelimiter))==std::string::npos || nEqu ==0) continue; std::string s1 = Transformer(strBuf.substr(0, nEqu)); std::string s2 = Transformer(strBuf.substr(nEqu+1)); #if 0 // defined (_DEBUG) OutputDebugStream("string-string-Parsing ->") << s1 << "<=>" << (s1 =="txtPassword" || s1 =="txtNewpassword"? std::string(s2.length(), '*') : s2) << "<"; #endif insert(std::pair(s1, s2)); } return *this; } string_pair_parser& add (const string_pair_parser& x) { for(const_iterator iter=x.begin() ; iter != x.end() ; ++iter) insert(*iter); return *this; } // // return *this* content as a string // operator std::string () const { return get_content_as_string(0); } std::string get_content_as_string(const char* extraSeparator="") const { std::string s; for(const_iterator iter=begin() ; iter != end() ; ++iter) { if(!s.empty()) { s +=_chSeparator; if(extraSeparator !=0 && extraSeparator[0] !='\0') s += extraSeparator; } s +=iter->first + _chDelimiter + iter->second; } return s; } template std::string get_content_with_transformation_as_string(TransformObject Transformer, const char* extraSeparator="") const { std::string s; for(const_iterator iter=begin() ; iter != end() ; ++iter) { if(!s.empty()) { s +=_chSeparator; if(extraSeparator !=0 && extraSeparator[0] !='\0') s += extraSeparator; } s +=Transformer(iter->first) + _chDelimiter + Transformer(iter->second); } return s; } /* template std::string get_content_with_transformation_as_string_of_XML_attributes(TrObject Transformator) const { std::string s; for(const_iterator iter=begin() ; iter != end() ; ++iter) s +=' ' +Transformator(iter->first) + "=\"" + Transformator(iter->second)+"\""; return s; } */ // // safe access to map. NOTE: the following will work on ONLY map/multimap container // std::string value_of(const std::string& key) const { if(!is_key_valid(key)) return std::string(); const_iterator it = find(key); return it == end()? std::string() : it->second; } std::string value_of(const char *key) const { return is_key_valid(key)? value_of(std::string(key)) : std::string() ; } bool empty (void) const { return Container::empty(); } bool empty (const char *key) const { return value_of(string(key)).empty(); } bool exists(const char *key) const { return is_key_valid(key)? find(key)!=end() : false; } bool empty (const std::string& key) const { return value_of(key).empty(); } bool exists(const std::string& key) const { return is_key_valid(key)? find(key)!=end() : false; } inline static bool is_key_valid(const char* key) { return key!=0 && key[0]!=char(); } inline static bool is_key_valid(const std::string& key) { return key.length()!=0 && key[0]!=char(); } // // stream / string output // std::ostream& getContent(std::ostream& os, const char *pszBOL=" ", const char *pszDelim="=",const char *pszEOL=";") const { for(const_iterator iter =begin() ; iter != end() ; ++iter) os << pszBOL << iter->first << pszDelim << iter->second << pszEOL; return os; } HTML& getContent(HTML& os) const { os << ""; getContent(os, "
NameValue
", "", "") << "
"; return os; } std::string getContentAsString(const char *pszBOL=" ", const char *pszDelim="=",const char *pszEOL=";") const { std::ostringstream s; getContentAsString(s, pszBOL, pszDelim, pszEOL); return s.str(); } std::string getContentAsHtml() const { HTML s; return (std::string)getContent(s); } }; ///////////////////////////////////////////////////////////////////////////////////////// // // HTTP helpers. QUERY STRING, POST data, and COOKIE. Note: both QueryString and cookies have // case-insensitive keys // typedef string_pair_parser<'&', '='> HTTP_POST_data; typedef string_pair_parser<'&', '=', std::map > HTTP_dictionary_cookie; typedef string_pair_parser<'&', '=', std::map > HTTP_query_string; typedef string_pair_parser<'\n',':', std::map > HTTP_headers; typedef string_pair_parser<'\n','=', std::map > INI; class GYS_SPEC HTTP_cookie : public string_pair_parser<';', '=', std::map > { typedef string_pair_parser<';', '=', std::map > base_class; public: typedef std::map::iterator iterator; typedef std::map::const_iterator const_iterator; typedef std::map::reverse_iterator reverse_iterator; typedef std::map::const_reverse_iterator const_reverse_iterator; explicit HTTP_cookie() {} explicit HTTP_cookie(const std::string& x) { add(x); } explicit HTTP_cookie(const char *x) { add(x); } explicit HTTP_cookie(const HTTP_cookie& x) { add(static_cast(x)); } // makes a copy HTTP_cookie& operator= (const HTTP_cookie& x) { assign(static_cast(x)); return *this; } HTTP_cookie& operator= (const char* x) { assign(x); return *this; } HTTP_cookie& operator= (const std::string& x) { assign(x); return *this; } HTTP_cookie& operator+= (const HTTP_cookie& x) { add(static_cast(x)); return *this; } HTTP_cookie& operator+= (const char* x) { add(x); return *this; } HTTP_cookie& operator+= (const std::string& x) { add(x); return *this; } operator std::string () const { return get_content_as_string(" "); } // // a helper to SET-COOKIE: // static std::string create_Cookie( const char *pszName, const char *pszValue, const char *pszPath, const char *pszDomain, int nSecs) { if(pszName==0 || pszName[0]=='\0') return ""; std::ostringstream s; s << pszName << "=" << (pszValue==0?"":pszValue); if(nSecs > 0) s << ";expires=" << CTimer::strGMTExpirationTime(nSecs); if(pszPath !=0 && pszPath[0] !='\0') s << ";path=" << pszPath; if(pszDomain!=0 && pszDomain[0]!='\0') s << ";domain=" << pszDomain; OutputDebugStream(s.str()); return s.str(); } static std::string create_Cookie_Header( const char *pszName, const char *pszValue, const char *pszPath, const char *pszDomain, int nSecs) { std::string s = create_Cookie(pszName, pszValue, pszPath, pszDomain, nSecs); if(s.length()) s +="\r\n"; return s; } static std::string create_SetCookie_Header( const char *pszName, const char *pszValue, const char *pszPath, const char *pszDomain, int nSecs) { if(pszName==0 || pszName[0]=='\0') return ""; return "Set-Cookie: " + create_Cookie_Header(pszName, pszValue, pszPath, pszDomain, nSecs); } static std::string getHtmlFormResetCookies(const std::string& strName="ResetCookies", const std::string& strInclude="") { return ""; } }; ////////////////////////////////////////////////////////////////////////////////////////// // // extesions to global HTML<< (with specfication of HTML::insert), and ostream<< // template inline HTML& operator<< (HTML& s, T& x){ return s.insert(x); } template<> inline HTML& HTML::insert(text_files_cache& x) { return x.getFileInformation(*this, std::string()); } //template<> inline HTML& HTML::insert(text_file& x) { return x.getFileVersion(*this); } template<> inline HTML& HTML::insert(FileVersion& x) { return x.getFileVersion(*this); } template<> inline HTML& HTML::insert(FileInformation& x) { return x.getFileInformation(*this); } template<> inline HTML& HTML::insert(CStatistics& x) { return x.getStatistics(*this); } template<> inline HTML& HTML::insert(HTTP_POST_data& x) { return x.getContent(*this); } template<> inline HTML& HTML::insert(HTTP_query_string& x) { return x.getContent(*this); } template<> inline HTML& HTML::insert(HTTP_cookie& x) { return x.getContent(*this); } inline std::ostream& operator<< (std::ostream& s, FileVersion& x) { return x.getFileVersion(s); } inline std::ostream& operator<< (std::ostream& s, FileInformation& x) { return x.getFileInformation(s); } inline std::ostream& operator<< (std::ostream& s, CStatistics& x) { return x.getStatistics(s); } inline std::ostream& operator<< (std::ostream& s, HTTP_POST_data& x) { return x.getContent(s); } inline std::ostream& operator<< (std::ostream& s, HTTP_query_string& x) { return x.getContent(s); } inline std::ostream& operator<< (std::ostream& s, HTTP_cookie& x) { return x.getContent(s); } //////////////////////////////////////////////////////////////////////////////////////////////////// // // class GYS_SPEC WIN32_thread { public: WIN32_thread() : m_ThreadID(0) , m_hThread(0) {} virtual ~WIN32_thread(); void terminate(int timeout=INFINITE); // void kill_thread(); void start(bool bYield=false); void post_WIN32_message(UINT msg, WPARAM wpar, LPARAM lpar); protected: UINT get_WIN32_message(MSG& msg, UINT first_message, UINT last_mesage); DWORD m_ThreadID; HANDLE m_hThread; private: virtual int thread_body() throw() = 0; friend DWORD WINAPI WIN32_thread_starter(LPVOID pthread); }; ///////////////////////////////////////////////////////////////////////////////////////////////////////////// // text clipboard class GYS_SPEC WINDOWS_Clipboard { public: static bool is_text_available() { return ::IsClipboardFormatAvailable(CF_TEXT) !=0; } static std::string get() { std::string res; if(is_text_available() && ::OpenClipboard(0)) { HANDLE hData = ::GetClipboardData(CF_TEXT); res = (char*)::GlobalLock(hData); ::GlobalUnlock(hData); ::CloseClipboard(); } return res; } static bool put(const char* pszSource, int length=-1) { if(pszSource ==0 || pszSource[0] ==0 || !::OpenClipboard(0)) return false; if(length <0) length = ::strlen(pszSource); ::EmptyClipboard(); HGLOBAL clipbuffer = ::GlobalAlloc(GMEM_DDESHARE, length+1); ::memcpy((char*)::GlobalLock(clipbuffer), pszSource, length+1); ::GlobalUnlock(clipbuffer); ::SetClipboardData(CF_TEXT,clipbuffer); ::CloseClipboard(); return true; } static bool put(const std::string& strSource) { return put(strSource.c_str(), strSource.length()); } }; class GYS_SPEC WINDOWS_WaitCursor { HCURSOR hOldCur; public: explicit WINDOWS_WaitCursor() : hOldCur(::SetCursor(::LoadCursor(0, IDC_WAIT))) {} ~WINDOWS_WaitCursor() { ::SetCursor(hOldCur); } }; #endif