summaryrefslogtreecommitdiff
path: root/zen/zstring.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'zen/zstring.cpp')
-rw-r--r--zen/zstring.cpp234
1 files changed, 234 insertions, 0 deletions
diff --git a/zen/zstring.cpp b/zen/zstring.cpp
new file mode 100644
index 00000000..5331499f
--- /dev/null
+++ b/zen/zstring.cpp
@@ -0,0 +1,234 @@
+// **************************************************************************
+// * This file is part of the FreeFileSync project. It is distributed under *
+// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
+// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
+// **************************************************************************
+
+#include "zstring.h"
+#include <stdexcept>
+#include <boost/thread/once.hpp>
+
+#ifdef FFS_WIN
+#include "dll.h"
+#include "win_ver.h"
+#endif
+
+#ifndef NDEBUG
+#include <iostream>
+#include <cstdlib>
+#endif
+
+using namespace zen;
+
+
+#ifndef NDEBUG
+LeakChecker::~LeakChecker()
+{
+ if (activeStrings.size() > 0)
+ {
+ int rowCount = 0;
+ std::string leakingStrings;
+
+ for (VoidPtrSizeMap::const_iterator i = activeStrings.begin();
+ i != activeStrings.end() && ++rowCount <= 20;
+ ++i)
+ leakingStrings += "\"" + rawMemToString(i->first, i->second) + "\"\n";
+
+ const std::string message = std::string("Memory leak detected!") + "\n\n"
+ + "Candidates:\n" + leakingStrings;
+#ifdef FFS_WIN
+ MessageBoxA(NULL, message.c_str(), "Error", 0);
+#else
+ std::cerr << message;
+ std::abort();
+#endif
+ }
+}
+
+
+LeakChecker& LeakChecker::instance()
+{
+ static LeakChecker inst;
+ return inst;
+}
+
+//caveat: function scope static initialization is not thread-safe in VS 2010! => make sure to call at app start!
+namespace
+{
+struct Dummy { Dummy() { LeakChecker::instance(); }} blah;
+}
+
+
+std::string LeakChecker::rawMemToString(const void* ptr, size_t size)
+{
+ std::string output = std::string(reinterpret_cast<const char*>(ptr), size);
+ output.erase(std::remove(output.begin(), output.end(), 0), output.end()); //remove intermediate 0-termination
+ if (output.size() > 100)
+ output.resize(100);
+ return output;
+}
+
+
+void LeakChecker::reportProblem(const std::string& message) //throw (std::logic_error)
+{
+#ifdef FFS_WIN
+ ::MessageBoxA(NULL, message.c_str(), "Error", 0);
+#else
+ std::cerr << message;
+#endif
+ throw std::logic_error("Memory leak! " + message);
+}
+#endif //NDEBUG
+
+
+#ifdef FFS_WIN
+namespace
+{
+#ifndef LOCALE_INVARIANT //invariant locale has been introduced with XP
+#define LOCALE_INVARIANT 0x007f
+#endif
+
+
+//warning: LOCALE_INVARIANT is NOT available with Windows 2000, so we have to make yet another distinction...
+const LCID ZSTRING_INVARIANT_LOCALE = zen::winXpOrLater() ?
+ LOCALE_INVARIANT :
+ MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); //see: http://msdn.microsoft.com/en-us/goglobal/bb688122.aspx
+
+
+//try to call "CompareStringOrdinal" for low-level string comparison: unfortunately available not before Windows Vista!
+//by a factor ~3 faster than old string comparison using "LCMapString"
+typedef int (WINAPI* CompareStringOrdinalFunc)(LPCWSTR lpString1,
+ int cchCount1,
+ LPCWSTR lpString2,
+ int cchCount2,
+ BOOL bIgnoreCase);
+SysDllFun<CompareStringOrdinalFunc> ordinalCompare; //caveat: function scope static initialization is not thread-safe in VS 2010!
+boost::once_flag initCmpStrOrdOnce = BOOST_ONCE_INIT;
+}
+
+
+int z_impl::compareFilenamesWin(const wchar_t* a, const wchar_t* b, size_t sizeA, size_t sizeB)
+{
+ boost::call_once(initCmpStrOrdOnce, []() { ordinalCompare = SysDllFun<CompareStringOrdinalFunc>(L"kernel32.dll", "CompareStringOrdinal"); });
+
+ if (ordinalCompare) //this additional test has no noticeable performance impact
+ {
+ const int rv = ordinalCompare(a, //pointer to first string
+ static_cast<int>(sizeA), //size, in bytes or characters, of first string
+ b, //pointer to second string
+ static_cast<int>(sizeB), //size, in bytes or characters, of second string
+ true); //ignore case
+ if (rv == 0)
+ throw std::runtime_error("Error comparing strings (ordinal)!");
+ else
+ return rv - 2; //convert to C-style string compare result
+ }
+ else //fallback
+ {
+ //do NOT use "CompareString"; this function is NOT accurate (even with LOCALE_INVARIANT and SORT_STRINGSORT): for example "weiß" == "weiss"!!!
+ //the only reliable way to compare filenames (with XP) is to call "CharUpper" or "LCMapString":
+
+ const int minSize = std::min<int>(sizeA, sizeB);
+
+ if (minSize == 0) //LCMapString does not allow input sizes of 0!
+ return static_cast<int>(sizeA) - static_cast<int>(sizeB);
+
+ int rv = 0; //always initialize...
+ if (minSize <= 5000) //performance optimization: stack
+ {
+ wchar_t bufferA[5000];
+ wchar_t bufferB[5000];
+
+ //faster than CharUpperBuff + wmemcpy or CharUpper + wmemcpy and same speed like ::CompareString()
+ if (::LCMapString(ZSTRING_INVARIANT_LOCALE, //__in LCID Locale,
+ LCMAP_UPPERCASE, //__in DWORD dwMapFlags,
+ a, //__in LPCTSTR lpSrcStr,
+ minSize, //__in int cchSrc,
+ bufferA, //__out LPTSTR lpDestStr,
+ 5000) == 0) //__in int cchDest
+ throw std::runtime_error("Error comparing strings! (LCMapString)");
+
+ if (::LCMapString(ZSTRING_INVARIANT_LOCALE, LCMAP_UPPERCASE, b, minSize, bufferB, 5000) == 0)
+ throw std::runtime_error("Error comparing strings! (LCMapString)");
+
+ rv = ::wmemcmp(bufferA, bufferB, minSize);
+ }
+ else //use freestore
+ {
+ std::vector<wchar_t> bufferA(minSize);
+ std::vector<wchar_t> bufferB(minSize);
+
+ if (::LCMapString(ZSTRING_INVARIANT_LOCALE, LCMAP_UPPERCASE, a, minSize, &bufferA[0], minSize) == 0)
+ throw std::runtime_error("Error comparing strings! (LCMapString: FS)");
+
+ if (::LCMapString(ZSTRING_INVARIANT_LOCALE, LCMAP_UPPERCASE, b, minSize, &bufferB[0], minSize) == 0)
+ throw std::runtime_error("Error comparing strings! (LCMapString: FS)");
+
+ rv = ::wmemcmp(&bufferA[0], &bufferB[0], minSize);
+ }
+
+ return rv == 0 ?
+ static_cast<int>(sizeA) - static_cast<int>(sizeB) :
+ rv;
+ }
+
+ // const int rv = CompareString(
+ // invariantLocale, //locale independent
+ // NORM_IGNORECASE | SORT_STRINGSORT, //comparison-style options
+ // a, //pointer to first string
+ // aCount, //size, in bytes or characters, of first string
+ // b, //pointer to second string
+ // bCount); //size, in bytes or characters, of second string
+ //
+ // if (rv == 0)
+ // throw std::runtime_error("Error comparing strings!");
+ // else
+ // return rv - 2; //convert to C-style string compare result
+}
+
+
+void z_impl::makeUpperCaseWin(wchar_t* str, size_t size)
+{
+ if (size == 0) //LCMapString does not allow input sizes of 0!
+ return;
+
+ //use Windows' upper case conversion: faster than ::CharUpper()
+ if (::LCMapString(ZSTRING_INVARIANT_LOCALE, LCMAP_UPPERCASE, str, static_cast<int>(size), str, static_cast<int>(size)) == 0)
+ throw std::runtime_error("Error converting to upper case! (LCMapString)");
+}
+
+
+/*
+#include <fstream>
+ extern std::wofstream statShared;
+extern std::wofstream statLowCapacity;
+extern std::wofstream statOverwrite;
+
+std::wstring p(ptr);
+p.erase(std::remove(p.begin(), p.end(), L'\n'), p.end());
+p.erase(std::remove(p.begin(), p.end(), L','), p.end());
+
+ if (descr(ptr)->refCount > 1)
+ statShared <<
+ minCapacity << L"," <<
+ descr(ptr)->refCount << L"," <<
+ descr(ptr)->length << L"," <<
+ descr(ptr)->capacity << L"," <<
+ p << L"\n";
+else if (minCapacity > descr(ptr)->capacity)
+ statLowCapacity <<
+ minCapacity << L"," <<
+ descr(ptr)->refCount << L"," <<
+ descr(ptr)->length << L"," <<
+ descr(ptr)->capacity << L"," <<
+ p << L"\n";
+else
+ statOverwrite <<
+ minCapacity << L"," <<
+ descr(ptr)->refCount << L"," <<
+ descr(ptr)->length << L"," <<
+ descr(ptr)->capacity << L"," <<
+ p << L"\n";
+*/
+
+#endif //FFS_WIN
bgstack15