From b59955bf2124b558147033782bf067a3723e4730 Mon Sep 17 00:00:00 2001 From: Nathan Yee Date: Tue, 14 Jul 2015 14:36:37 -0700 Subject: online update tdf#68274: fix --enable-online-update=mar on Windows Change-Id: I397566ae2488799399cad361b24a281d3599cc5b --- onlineupdate/Executable_mar.mk | 7 + onlineupdate/Executable_updater.mk | 41 +- onlineupdate/source/libmar/sign/mar_sign.c | 4 +- onlineupdate/source/libmar/sign/nss_secutil.c | 4 +- onlineupdate/source/libmar/src/mar.h | 2 +- onlineupdate/source/libmar/src/mar_create.c | 2 +- onlineupdate/source/libmar/src/mar_extract.c | 6 +- onlineupdate/source/libmar/src/mar_private.h | 2 +- onlineupdate/source/libmar/src/mar_read.c | 4 +- onlineupdate/source/libmar/tool/mar.c | 24 +- onlineupdate/source/libmar/verify/cryptox.c | 4 +- onlineupdate/source/libmar/verify/cryptox.h | 4 +- onlineupdate/source/libmar/verify/mar_verify.c | 2 +- onlineupdate/source/update/common/readstrings.h | 1 + onlineupdate/source/update/common/updatehelper.cxx | 1 - onlineupdate/source/update/inc/mozilla/Char16.h | 239 ++++++++ onlineupdate/source/update/inc/mozilla/Move.h | 238 ++++++++ onlineupdate/source/update/inc/mozilla/Pair.h | 219 +++++++ onlineupdate/source/update/inc/mozilla/UniquePtr.h | 659 ++++++++++++++++++++ onlineupdate/source/update/inc/nsAutoRef.h | 670 +++++++++++++++++++++ onlineupdate/source/update/inc/nsWindowsHelpers.h | 159 +++++ onlineupdate/source/update/src/mar.h | 2 +- onlineupdate/source/update/src/mar_create.c | 2 +- onlineupdate/source/update/src/mar_extract.c | 6 +- onlineupdate/source/update/src/mar_private.h | 2 +- onlineupdate/source/update/src/mar_read.c | 4 +- .../source/update/updater/archivereader.cxx | 1 - onlineupdate/source/update/updater/loaddlls.cxx | 3 + .../source/update/updater/nsWindowsRestart.cxx | 584 ++++++++++++++++++ .../source/update/updater/progressui_win.cxx | 3 + onlineupdate/source/update/updater/updater.cxx | 2 +- .../updater/xpcom/glue/nsVersionComparator.cxx | 19 +- .../updater/xpcom/glue/nsVersionComparator.h | 14 +- 33 files changed, 2875 insertions(+), 59 deletions(-) create mode 100644 onlineupdate/source/update/inc/mozilla/Char16.h create mode 100644 onlineupdate/source/update/inc/mozilla/Move.h create mode 100644 onlineupdate/source/update/inc/mozilla/Pair.h create mode 100644 onlineupdate/source/update/inc/mozilla/UniquePtr.h create mode 100644 onlineupdate/source/update/inc/nsAutoRef.h create mode 100644 onlineupdate/source/update/inc/nsWindowsHelpers.h create mode 100644 onlineupdate/source/update/updater/nsWindowsRestart.cxx (limited to 'onlineupdate') diff --git a/onlineupdate/Executable_mar.mk b/onlineupdate/Executable_mar.mk index 391f272d11eb..7a42b3ca437d 100644 --- a/onlineupdate/Executable_mar.mk +++ b/onlineupdate/Executable_mar.mk @@ -17,6 +17,13 @@ $(eval $(call gb_Executable_set_include,mar,\ $$(INCLUDE) \ )) +ifeq ($(OS),WNT) +$(eval $(call gb_Executable_add_libs,mar,\ + ws2_32.lib \ + Crypt32.lib \ +)) +endif + $(eval $(call gb_Executable_use_externals,mar,nss3)) $(eval $(call gb_Executable_add_cobjects,mar,\ diff --git a/onlineupdate/Executable_updater.mk b/onlineupdate/Executable_updater.mk index a4c4f9563108..eb94e8b92610 100644 --- a/onlineupdate/Executable_updater.mk +++ b/onlineupdate/Executable_updater.mk @@ -9,6 +9,15 @@ $(eval $(call gb_Executable_Executable,updater)) +ifeq ($(OS),WNT) +$(eval $(call gb_Executable_set_include,updater,\ + -I$(SRCDIR)/onlineupdate/source/update/src \ + -I$(SRCDIR)/onlineupdate/source/update/inc \ + -I$(SRCDIR)/onlineupdate/source/update/common \ + -I$(SRCDIR)/onlineupdate/source/update/updater/xpcom/glue \ + $$(INCLUDE) \ +)) +else $(eval $(call gb_Executable_set_include,updater,\ -I$(SRCDIR)/onlineupdate/source/update/src \ -I$(SRCDIR)/onlineupdate/source/update/inc \ @@ -17,22 +26,36 @@ $(eval $(call gb_Executable_set_include,updater,\ -lpthread \ $$(INCLUDE) \ )) +endif +ifeq ($(OS),WNT) +$(eval $(call gb_Executable_add_libs,updater,\ + Ws2_32.lib \ + Gdi32.lib \ + Comctl32.lib \ + Shell32.lib \ + Shlwapi.lib \ +)) +else $(eval $(call gb_Executable_add_libs,updater,\ - -lX11 \ - -lXext \ - -lXrender \ - -lSM \ - -lICE \ + -lX11 \ + -lXext \ + -lXrender \ + -lSM \ + -lICE \ + $(GTK3_LIBS) \ )) +endif +ifeq ($(OS),WNT) $(eval $(call gb_Executable_add_cxxflags,updater,\ - $$(GTK3_CFLAGS) \ + /Zc:wchar_t \ )) - -$(eval $(call gb_Executable_add_libs,updater,\ - $(GTK3_LIBS) \ +else +$(eval $(call gb_Executable_add_cxxflags,updater,\ + $$(GTK3_CFLAGS) \ )) +endif $(eval $(call gb_Executable_use_externals,updater,\ gtk \ diff --git a/onlineupdate/source/libmar/sign/mar_sign.c b/onlineupdate/source/libmar/sign/mar_sign.c index 775b545cf346..4a5fe87fd402 100644 --- a/onlineupdate/source/libmar/sign/mar_sign.c +++ b/onlineupdate/source/libmar/sign/mar_sign.c @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifdef XP_WIN +#ifdef WNT #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif @@ -17,7 +17,7 @@ #include "mar_cmdline.h" #include "mar.h" #include "cryptox.h" -#ifndef XP_WIN +#ifndef WNT #include #endif diff --git a/onlineupdate/source/libmar/sign/nss_secutil.c b/onlineupdate/source/libmar/sign/nss_secutil.c index b98834c46141..caa124e651d7 100644 --- a/onlineupdate/source/libmar/sign/nss_secutil.c +++ b/onlineupdate/source/libmar/sign/nss_secutil.c @@ -8,14 +8,14 @@ #include "nss_secutil.h" #include "prprf.h" -#ifdef XP_WIN +#ifdef WNT #include #else #include #endif static char consoleName[] = { -#ifdef XP_UNIX +#ifdef UNIX "/dev/tty" #else "CON:" diff --git a/onlineupdate/source/libmar/src/mar.h b/onlineupdate/source/libmar/src/mar.h index 0e9dc1f137bd..31cc3934e395 100644 --- a/onlineupdate/source/libmar/src/mar.h +++ b/onlineupdate/source/libmar/src/mar.h @@ -69,7 +69,7 @@ typedef int (* MarItemCallback)(MarFile *mar, const MarItem *item, void *data); */ MarFile *mar_open(const char *path); -#ifdef XP_WIN +#ifdef WNT MarFile *mar_wopen(const wchar_t *path); #endif diff --git a/onlineupdate/source/libmar/src/mar_create.c b/onlineupdate/source/libmar/src/mar_create.c index c2ce10126cbd..a87e937fe4a3 100644 --- a/onlineupdate/source/libmar/src/mar_create.c +++ b/onlineupdate/source/libmar/src/mar_create.c @@ -13,7 +13,7 @@ #include "mar_cmdline.h" #include "mar.h" -#ifdef XP_WIN +#ifdef WNT #include #else #include diff --git a/onlineupdate/source/libmar/src/mar_extract.c b/onlineupdate/source/libmar/src/mar_extract.c index ec1cd6c53446..f3512e99122c 100644 --- a/onlineupdate/source/libmar/src/mar_extract.c +++ b/onlineupdate/source/libmar/src/mar_extract.c @@ -12,7 +12,7 @@ #include "mar_private.h" #include "mar.h" -#ifdef XP_WIN +#ifdef WNT #include #include #endif @@ -25,7 +25,7 @@ static int mar_ensure_parent_dir(const char *path) { *slash = '\0'; mar_ensure_parent_dir(path); -#ifdef XP_WIN +#ifdef WNT _mkdir(path); #else mkdir(path, 0755); @@ -43,7 +43,7 @@ static int mar_test_callback(MarFile *mar, const MarItem *item, void *unused) { if (mar_ensure_parent_dir(item->name)) return -1; -#ifdef XP_WIN +#ifdef WNT fd = _open(item->name, _O_BINARY|_O_CREAT|_O_TRUNC|_O_WRONLY, item->flags); #else fd = creat(item->name, item->flags); diff --git a/onlineupdate/source/libmar/src/mar_private.h b/onlineupdate/source/libmar/src/mar_private.h index 8a7fb45ccd82..39a77d1ac03e 100644 --- a/onlineupdate/source/libmar/src/mar_private.h +++ b/onlineupdate/source/libmar/src/mar_private.h @@ -53,7 +53,7 @@ MOZ_STATIC_ASSERT(sizeof(BLOCKSIZE) < \ /* The mar program is compiled as a host bin so we don't have access to NSPR at runtime. For that reason we use ntohl, htonl, and define HOST_TO_NETWORK64 instead of the NSPR equivalents. */ -#ifdef XP_WIN +#ifdef WNT #include #define ftello _ftelli64 #define fseeko _fseeki64 diff --git a/onlineupdate/source/libmar/src/mar_read.c b/onlineupdate/source/libmar/src/mar_read.c index 7be225385403..c7c4bdf19554 100644 --- a/onlineupdate/source/libmar/src/mar_read.c +++ b/onlineupdate/source/libmar/src/mar_read.c @@ -11,7 +11,7 @@ #include "mar_private.h" #include "mar.h" -#ifdef XP_WIN +#ifdef WNT #include #else #include @@ -177,7 +177,7 @@ MarFile *mar_open(const char *path) { return mar_fpopen(fp); } -#ifdef XP_WIN +#ifdef WNT MarFile *mar_wopen(const wchar_t *path) { FILE *fp; diff --git a/onlineupdate/source/libmar/tool/mar.c b/onlineupdate/source/libmar/tool/mar.c index 9a50b387f839..9a961ae9aabd 100644 --- a/onlineupdate/source/libmar/tool/mar.c +++ b/onlineupdate/source/libmar/tool/mar.c @@ -10,7 +10,7 @@ #include "mar.h" #include "mar_cmdline.h" -#ifdef XP_WIN +#ifdef WNT #include #include #define chdir _chdir @@ -23,7 +23,7 @@ #define MAR_CHANNEL_ID "LOOnlineUpdater" /* Dummy value; replace or remove in the future */ -#if !defined(NO_SIGN_VERIFY) && (!defined(XP_WIN) || defined(MAR_NSS)) +#if !defined(NO_SIGN_VERIFY) && (!defined(WNT) || defined(MAR_NSS)) #include "cert.h" #include "pk11pub.h" int NSSInitCryptoContext(const char *NSSConfigDir); @@ -66,7 +66,7 @@ static void print_usage() { "signed_input_archive.mar base_64_encoded_signature_file " "changed_signed_output.mar\n"); printf("(i) is the index of the certificate to extract\n"); -#if defined(XP_MACOSX) || (defined(XP_WIN) && !defined(MAR_NSS)) +#if defined(MACOSX) || (defined(WNT) && !defined(MAR_NSS)) printf("Verify a MAR file:\n"); printf(" mar [-C workingDir] -D DERFilePath -v signed_archive.mar\n"); printf("At most %d signature certificate DER files are specified by " @@ -131,17 +131,17 @@ int main(int argc, char **argv) { uint32_t fileSizes[MAX_SIGNATURES]; const uint8_t* certBuffers[MAX_SIGNATURES]; char* DERFilePaths[MAX_SIGNATURES]; -#if (!defined(XP_WIN) && !defined(XP_MACOSX)) || defined(MAR_NSS) +#if (!defined(WNT) && !defined(MACOSX)) || defined(MAR_NSS) CERTCertificate* certs[MAX_SIGNATURES]; #endif #endif memset((void*)certNames, 0, sizeof(certNames)); -#if defined(XP_WIN) && !defined(MAR_NSS) && !defined(NO_SIGN_VERIFY) +#if defined(WNT) && !defined(MAR_NSS) && !defined(NO_SIGN_VERIFY) memset((void*)certBuffers, 0, sizeof(certBuffers)); #endif -#if !defined(NO_SIGN_VERIFY) && ((!defined(MAR_NSS) && defined(XP_WIN)) || \ - defined(XP_MACOSX)) +#if !defined(NO_SIGN_VERIFY) && ((!defined(MAR_NSS) && defined(WNT)) || \ + defined(MACOSX)) memset(DERFilePaths, 0, sizeof(DERFilePaths)); memset(fileSizes, 0, sizeof(fileSizes)); #endif @@ -170,8 +170,8 @@ int main(int argc, char **argv) { argv += 2; argc -= 2; } -#if !defined(NO_SIGN_VERIFY) && ((!defined(MAR_NSS) && defined(XP_WIN)) || \ - defined(XP_MACOSX)) +#if !defined(NO_SIGN_VERIFY) && ((!defined(MAR_NSS) && defined(WNT)) || \ + defined(MACOSX)) /* -D DERFilePath, also matches -D[index] DERFilePath We allow an index for verifying to be symmetric with the import and export command line arguments. */ @@ -329,7 +329,7 @@ int main(int argc, char **argv) { return -1; } -#if (!defined(XP_WIN) && !defined(XP_MACOSX)) || defined(MAR_NSS) +#if (!defined(WNT) && !defined(MACOSX)) || defined(MAR_NSS) if (!NSSConfigDir || certCount == 0) { print_usage(); return -1; @@ -343,7 +343,7 @@ int main(int argc, char **argv) { rv = 0; for (k = 0; k < certCount; ++k) { -#if (defined(XP_WIN) || defined(XP_MACOSX)) && !defined(MAR_NSS) +#if (defined(WNT) || defined(MACOSX)) && !defined(MAR_NSS) rv = mar_read_entire_file(DERFilePaths[k], MAR_MAX_CERT_SIZE, &certBuffers[k], &fileSizes[k]); #else @@ -380,7 +380,7 @@ int main(int argc, char **argv) { } } for (k = 0; k < certCount; ++k) { -#if (defined(XP_WIN) || defined(XP_MACOSX)) && !defined(MAR_NSS) +#if (defined(WNT) || defined(MACOSX)) && !defined(MAR_NSS) free((void*)certBuffers[k]); #else /* certBuffers[k] is owned by certs[k] so don't free it */ diff --git a/onlineupdate/source/libmar/verify/cryptox.c b/onlineupdate/source/libmar/verify/cryptox.c index 106ec29d8a27..b1859b72c749 100644 --- a/onlineupdate/source/libmar/verify/cryptox.c +++ b/onlineupdate/source/libmar/verify/cryptox.c @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifdef XP_WIN +#ifdef WNT #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif @@ -99,7 +99,7 @@ NSS_VerifySignature(VFYContext * const *ctx, return SECSuccess == status ? CryptoX_Success : CryptoX_Error; } -#elif defined(XP_WIN) +#elif defined(WNT) /** * Verifies if a signature + public key matches a hash context. * diff --git a/onlineupdate/source/libmar/verify/cryptox.h b/onlineupdate/source/libmar/verify/cryptox.h index 9cca033a299e..8b926814a70b 100644 --- a/onlineupdate/source/libmar/verify/cryptox.h +++ b/onlineupdate/source/libmar/verify/cryptox.h @@ -57,7 +57,7 @@ CryptoX_Result NSS_VerifySignature(VFYContext * const *ctx , #define CryptoX_FreeCertificate(cert) \ CERT_DestroyCertificate(*cert) -#elif XP_MACOSX +#elif MACOSX #define CryptoX_InvalidHandleValue NULL #define CryptoX_ProviderHandle void* @@ -104,7 +104,7 @@ void CryptoMac_FreePublicKey(CryptoX_PublicKey* aPublicKey); CryptoMac_FreePublicKey(aPublicKey) #define CryptoX_FreeCertificate(aCertificate) -#elif defined(XP_WIN) +#elif defined(WNT) #include #include diff --git a/onlineupdate/source/libmar/verify/mar_verify.c b/onlineupdate/source/libmar/verify/mar_verify.c index 6c421b27d08a..954fbbb5e659 100644 --- a/onlineupdate/source/libmar/verify/mar_verify.c +++ b/onlineupdate/source/libmar/verify/mar_verify.c @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifdef XP_WIN +#ifdef WNT #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif diff --git a/onlineupdate/source/update/common/readstrings.h b/onlineupdate/source/update/common/readstrings.h index 99e515daa611..ecef9aa5e6b9 100644 --- a/onlineupdate/source/update/common/readstrings.h +++ b/onlineupdate/source/update/common/readstrings.h @@ -10,6 +10,7 @@ #define MAX_TEXT_LEN 600 #ifdef WNT +# define UNICODE # include typedef WCHAR NS_tchar; #else diff --git a/onlineupdate/source/update/common/updatehelper.cxx b/onlineupdate/source/update/common/updatehelper.cxx index 579515430115..3e91feae3253 100644 --- a/onlineupdate/source/update/common/updatehelper.cxx +++ b/onlineupdate/source/update/common/updatehelper.cxx @@ -22,7 +22,6 @@ using mozilla::MakeUnique; using mozilla::UniquePtr; -WCHAR* MakeCommandLine(int argc, WCHAR **argv); BOOL PathAppendSafe(LPWSTR base, LPCWSTR extra); /** diff --git a/onlineupdate/source/update/inc/mozilla/Char16.h b/onlineupdate/source/update/inc/mozilla/Char16.h new file mode 100644 index 000000000000..f07494f7f47f --- /dev/null +++ b/onlineupdate/source/update/inc/mozilla/Char16.h @@ -0,0 +1,239 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Implements a UTF-16 character type. */ + +#ifndef mozilla_Char16_h +#define mozilla_Char16_h + +#ifdef __cplusplus + +/* + * C++11 introduces a char16_t type and support for UTF-16 string and character + * literals. C++11's char16_t is a distinct builtin type. Technically, char16_t + * is a 16-bit code unit of a Unicode code point, not a "character". + */ + +#if defined(_MSC_VER) && _MSC_VER < 1900 + /* + * C++11 says char16_t is a distinct builtin type, but Windows's yvals.h + * typedefs char16_t as an unsigned short prior to MSVC 2015, which + * implemented C++11's distinct char16_t type. We would like to alias + * char16_t to Windows's 16-bit wchar_t so we can declare UTF-16 literals as + * constant expressions (and pass char16_t pointers to Windows APIs). We + * #define _CHAR16T here in order to prevent yvals.h from overriding our + * char16_t typedefs, which we set to wchar_t for C++ code. + * + * In addition, #defining _CHAR16T will prevent yvals.h from defining a + * char32_t type, so we have to undo that damage here and provide our own, + * which is identical to the yvals.h type. + */ +# define MOZ_UTF16_HELPER(s) L##s +# define _CHAR16T +typedef wchar_t char16_t; +typedef unsigned int char32_t; +#else + /* C++11 has a builtin char16_t type. */ +# define MOZ_UTF16_HELPER(s) u##s + /** + * This macro is used to distinguish when char16_t would be a distinct + * typedef from wchar_t. + */ +# define MOZ_CHAR16_IS_NOT_WCHAR +# ifdef WIN32 +# define MOZ_USE_CHAR16_WRAPPER +# endif +#endif + +#ifdef MOZ_USE_CHAR16_WRAPPER +# include + /** + * Win32 API extensively uses wchar_t, which is represented by a separated + * builtin type than char16_t per spec. It's not the case for MSVC prior to + * MSVC 2015, but other compilers follow the spec. We want to mix wchar_t and + * char16_t on Windows builds. This class is supposed to make it easier. It + * stores char16_t const pointer, but provides implicit casts for wchar_t as + * well. On other platforms, we simply use + * |typedef const char16_t* char16ptr_t|. Here, we want to make the class as + * similar to this typedef, including providing some casts that are allowed + * by the typedef. + */ +class char16ptr_t +{ +private: + const char16_t* mPtr; + static_assert(sizeof(char16_t) == sizeof(wchar_t), + "char16_t and wchar_t sizes differ"); + +public: + char16ptr_t(const char16_t* aPtr) : mPtr(aPtr) {} + char16ptr_t(const wchar_t* aPtr) : + mPtr(reinterpret_cast(aPtr)) + {} + + /* Without this, nullptr assignment would be ambiguous. */ + constexpr char16ptr_t(decltype(nullptr)) : mPtr(nullptr) {} + + operator const char16_t*() const + { + return mPtr; + } + operator const wchar_t*() const + { + return reinterpret_cast(mPtr); + } + operator const void*() const + { + return mPtr; + } + operator bool() const + { + return mPtr != nullptr; + } + operator std::wstring() const + { + return std::wstring(static_cast(*this)); + } + + /* Explicit cast operators to allow things like (char16_t*)str. */ + explicit operator char16_t*() const + { + return const_cast(mPtr); + } + explicit operator wchar_t*() const + { + return const_cast(static_cast(*this)); + } + explicit operator int() const + { + return reinterpret_cast(mPtr); + } + explicit operator unsigned int() const + { + return reinterpret_cast(mPtr); + } + explicit operator long() const + { + return reinterpret_cast(mPtr); + } + explicit operator unsigned long() const + { + return reinterpret_cast(mPtr); + } + explicit operator long long() const + { + return reinterpret_cast(mPtr); + } + explicit operator unsigned long long() const + { + return reinterpret_cast(mPtr); + } + + /** + * Some Windows API calls accept BYTE* but require that data actually be + * WCHAR*. Supporting this requires explicit operators to support the + * requisite explicit casts. + */ + explicit operator const char*() const + { + return reinterpret_cast(mPtr); + } + explicit operator const unsigned char*() const + { + return reinterpret_cast(mPtr); + } + explicit operator unsigned char*() const + { + return + const_cast(reinterpret_cast(mPtr)); + } + explicit operator void*() const + { + return const_cast(mPtr); + } + + /* Some operators used on pointers. */ + char16_t operator[](size_t aIndex) const + { + return mPtr[aIndex]; + } + bool operator==(const char16ptr_t& aOther) const + { + return mPtr == aOther.mPtr; + } + bool operator==(decltype(nullptr)) const + { + return mPtr == nullptr; + } + bool operator!=(const char16ptr_t& aOther) const + { + return mPtr != aOther.mPtr; + } + bool operator!=(decltype(nullptr)) const + { + return mPtr != nullptr; + } + char16ptr_t operator+(int aValue) const + { + return char16ptr_t(mPtr + aValue); + } + char16ptr_t operator+(unsigned int aValue) const + { + return char16ptr_t(mPtr + aValue); + } + char16ptr_t operator+(long aValue) const + { + return char16ptr_t(mPtr + aValue); + } + char16ptr_t operator+(unsigned long aValue) const + { + return char16ptr_t(mPtr + aValue); + } + char16ptr_t operator+(long long aValue) const + { + return char16ptr_t(mPtr + aValue); + } + char16ptr_t operator+(unsigned long long aValue) const + { + return char16ptr_t(mPtr + aValue); + } + ptrdiff_t operator-(const char16ptr_t& aOther) const + { + return mPtr - aOther.mPtr; + } +}; + +inline decltype((char*)0-(char*)0) +operator-(const char16_t* aX, const char16ptr_t aY) +{ + return aX - static_cast(aY); +} + +#else + +typedef const char16_t* char16ptr_t; + +#endif + +/* + * Macro arguments used in concatenation or stringification won't be expanded. + * Therefore, in order for |MOZ_UTF16(FOO)| to work as expected (which is to + * expand |FOO| before doing whatever |MOZ_UTF16| needs to do to it) a helper + * macro, |MOZ_UTF16_HELPER| needs to be inserted in between to allow the macro + * argument to expand. See "3.10.6 Separate Expansion of Macro Arguments" of the + * CPP manual for a more accurate and precise explanation. + */ +#define MOZ_UTF16(s) MOZ_UTF16_HELPER(s) + +static_assert(sizeof(char16_t) == 2, "Is char16_t type 16 bits?"); +static_assert(char16_t(-1) > char16_t(0), "Is char16_t type unsigned?"); +static_assert(sizeof(MOZ_UTF16('A')) == 2, "Is char literal 16 bits?"); +static_assert(sizeof(MOZ_UTF16("")[0]) == 2, "Is string char 16 bits?"); + +#endif + +#endif /* mozilla_Char16_h */ + diff --git a/onlineupdate/source/update/inc/mozilla/Move.h b/onlineupdate/source/update/inc/mozilla/Move.h new file mode 100644 index 000000000000..f6d0bfc1ca38 --- /dev/null +++ b/onlineupdate/source/update/inc/mozilla/Move.h @@ -0,0 +1,238 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* C++11-style, but C++98-usable, "move references" implementation. */ + +#ifndef mozilla_Move_h +#define mozilla_Move_h + +#include "mozilla/TypeTraits.h" + +namespace mozilla { + +/* + * "Move" References + * + * Some types can be copied much more efficiently if we know the original's + * value need not be preserved --- that is, if we are doing a "move", not a + * "copy". For example, if we have: + * + * Vector u; + * Vector v(u); + * + * the constructor for v must apply a copy constructor to each element of u --- + * taking time linear in the length of u. However, if we know we will not need u + * any more once v has been initialized, then we could initialize v very + * efficiently simply by stealing u's dynamically allocated buffer and giving it + * to v --- a constant-time operation, regardless of the size of u. + * + * Moves often appear in container implementations. For example, when we append + * to a vector, we may need to resize its buffer. This entails moving each of + * its extant elements from the old, smaller buffer to the new, larger buffer. + * But once the elements have been migrated, we're just going to throw away the + * old buffer; we don't care if they still have their values. So if the vector's + * element type can implement "move" more efficiently than "copy", the vector + * resizing should by all means use a "move" operation. Hash tables should also + * use moves when resizing their internal array as entries are added and + * removed. + * + * The details of the optimization, and whether it's worth applying, vary + * from one type to the next: copying an 'int' is as cheap as moving it, so + * there's no benefit in distinguishing 'int' moves from copies. And while + * some constructor calls for complex types are moves, many really have to + * be copies, and can't be optimized this way. So we need: + * + * 1) a way for a type (like Vector) to announce that it can be moved more + * efficiently than it can be copied, and provide an implementation of that + * move operation; and + * + * 2) a way for a particular invocation of a copy constructor to say that it's + * really a move, not a copy, and that the value of the original isn't + * important afterwards (although it must still be safe to destroy). + * + * If a constructor has a single argument of type 'T&&' (an 'rvalue reference + * to T'), that indicates that it is a 'move constructor'. That's 1). It should + * move, not copy, its argument into the object being constructed. It may leave + * the original in any safely-destructible state. + * + * If a constructor's argument is an rvalue, as in 'C(f(x))' or 'C(x + y)', as + * opposed to an lvalue, as in 'C(x)', then overload resolution will prefer the + * move constructor, if there is one. The 'mozilla::Move' function, defined in + * this file, is an identity function you can use in a constructor invocation to + * make any argument into an rvalue, like this: C(Move(x)). That's 2). (You + * could use any function that works, but 'Move' indicates your intention + * clearly.) + * + * Where we might define a copy constructor for a class C like this: + * + * C(const C& rhs) { ... copy rhs to this ... } + * + * we would declare a move constructor like this: + * + * C(C&& rhs) { .. move rhs to this ... } + * + * And where we might perform a copy like this: + * + * C c2(c1); + * + * we would perform a move like this: + * + * C c2(Move(c1)); + * + * Note that 'T&&' implicitly converts to 'T&'. So you can pass a 'T&&' to an + * ordinary copy constructor for a type that doesn't support a special move + * constructor, and you'll just get a copy. This means that templates can use + * Move whenever they know they won't use the original value any more, even if + * they're not sure whether the type at hand has a specialized move constructor. + * If it doesn't, the 'T&&' will just convert to a 'T&', and the ordinary copy + * constructor will apply. + * + * A class with a move constructor can also provide a move assignment operator. + * A generic definition would run this's destructor, and then apply the move + * constructor to *this's memory. A typical definition: + * + * C& operator=(C&& rhs) { + * MOZ_ASSERT(&rhs != this, "self-moves are prohibited"); + * this->~C(); + * new(this) C(Move(rhs)); + * return *this; + * } + * + * With that in place, one can write move assignments like this: + * + * c2 = Move(c1); + * + * This destroys c2, moves c1's value to c2, and leaves c1 in an undefined but + * destructible state. + * + * As we say, a move must leave the original in a "destructible" state. The + * original's destructor will still be called, so if a move doesn't + * actually steal all its resources, that's fine. We require only that the + * move destination must take on the original's value; and that destructing + * the original must not break the move destination. + * + * (Opinions differ on whether move assignment operators should deal with move + * assignment of an object onto itself. It seems wise to either handle that + * case, or assert that it does not occur.) + * + * Forwarding: + * + * Sometimes we want copy construction or assignment if we're passed an ordinary + * value, but move construction if passed an rvalue reference. For example, if + * our constructor takes two arguments and either could usefully be a move, it + * seems silly to write out all four combinations: + * + * C::C(X& x, Y& y) : x(x), y(y) { } + * C::C(X& x, Y&& y) : x(x), y(Move(y)) { } + * C::C(X&& x, Y& y) : x(Move(x)), y(y) { } + * C::C(X&& x, Y&& y) : x(Move(x)), y(Move(y)) { } + * + * To avoid this, C++11 has tweaks to make it possible to write what you mean. + * The four constructor overloads above can be written as one constructor + * template like so[0]: + * + * template + * C::C(XArg&& x, YArg&& y) : x(Forward(x)), y(Forward(y)) { } + * + * ("'Don't Repeat Yourself'? What's that?") + * + * This takes advantage of two new rules in C++11: + * + * - First, when a function template takes an argument that is an rvalue + * reference to a template argument (like 'XArg&& x' and 'YArg&& y' above), + * then when the argument is applied to an lvalue, the template argument + * resolves to 'T&'; and when it is applied to an rvalue, the template + * argument resolves to 'T'. Thus, in a call to C::C like: + * + * X foo(int); + * Y yy; + * + * C(foo(5), yy) + * + * XArg would resolve to 'X', and YArg would resolve to 'Y&'. + * + * - Second, Whereas C++ used to forbid references to references, C++11 defines + * 'collapsing rules': 'T& &', 'T&& &', and 'T& &&' (that is, any combination + * involving an lvalue reference) now collapse to simply 'T&'; and 'T&& &&' + * collapses to 'T&&'. + * + * Thus, in the call above, 'XArg&&' is 'X&&'; and 'YArg&&' is 'Y& &&', which + * collapses to 'Y&'. Because the arguments are declared as rvalue references + * to template arguments, the lvalue-ness "shines through" where present. + * + * Then, the 'Forward' function --- you must invoke 'Forward' with its type + * argument --- returns an lvalue reference or an rvalue reference to its + * argument, depending on what T is. In our unified constructor definition, that + * means that we'll invoke either the copy or move constructors for x and y, + * depending on what we gave C's constructor. In our call, we'll move 'foo()' + * into 'x', but copy 'yy' into 'y'. + * + * This header file defines Move and Forward in the mozilla namespace. It's up + * to individual containers to annotate moves as such, by calling Move; and it's + * up to individual types to define move constructors and assignment operators + * when valuable. + * + * (C++11 says that the header file should define 'std::move' and + * 'std::forward', which are just like our 'Move' and 'Forward'; but those + * definitions aren't available in that header on all our platforms, so we + * define them ourselves here.) + * + * 0. This pattern is known as "perfect forwarding". Interestingly, it is not + * actually perfect, and it can't forward all possible argument expressions! + * There is a C++11 issue: you can't form a reference to a bit-field. As a + * workaround, assign the bit-field to a local variable and use that: + * + * // C is as above + * struct S { int x : 1; } s; + * C(s.x, 0); // BAD: s.x is a reference to a bit-field, can't form those + * int tmp = s.x; + * C(tmp, 0); // OK: tmp not a bit-field + */ + +/** + * Identical to std::Move(); this is necessary until our stlport supports + * std::move(). + */ +template +inline typename RemoveReference::Type&& +Move(T&& aX) +{ + return static_cast::Type&&>(aX); +} + +/** + * These two overloads are identical to std::forward(); they are necessary until + * our stlport supports std::forward(). + */ +template +inline T&& +Forward(typename RemoveReference::Type& aX) +{ + return static_cast(aX); +} + +template +inline T&& +Forward(typename RemoveReference::Type&& aX) +{ + static_assert(!IsLvalueReference::value, + "misuse of Forward detected! try the other overload"); + return static_cast(aX); +} + +/** Swap |aX| and |aY| using move-construction if possible. */ +template +inline void +Swap(T& aX, T& aY) +{ + T tmp(Move(aX)); + aX = Move(aY); + aY = Move(tmp); +} + +} // namespace mozilla + +#endif /* mozilla_Move_h */ diff --git a/onlineupdate/source/update/inc/mozilla/Pair.h b/onlineupdate/source/update/inc/mozilla/Pair.h new file mode 100644 index 000000000000..ad7b86a29c62 --- /dev/null +++ b/onlineupdate/source/update/inc/mozilla/Pair.h @@ -0,0 +1,219 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* A class holding a pair of objects that tries to conserve storage space. */ + +#ifndef mozilla_Pair_h +#define mozilla_Pair_h + +#include "mozilla/Attributes.h" +#include "mozilla/Move.h" +#include "mozilla/TypeTraits.h" + +namespace mozilla { + +namespace detail { + +enum StorageType { AsBase, AsMember }; + +// Optimize storage using the Empty Base Optimization -- that empty base classes +// don't take up space -- to optimize size when one or the other class is +// stateless and can be used as a base class. +// +// The extra conditions on storage for B are necessary so that PairHelper won't +// ambiguously inherit from either A or B, such that one or the other base class +// would be inaccessible. +template::value ? detail::AsBase : detail::AsMember, + detail::StorageType = + IsEmpty::value && !IsBaseOf::value && !IsBaseOf::value + ? detail::AsBase + : detail::AsMember> +struct PairHelper; + +template +struct PairHelper +{ +protected: + template + PairHelper(AArg&& aA, BArg&& aB) + : mFirstA(Forward(aA)), + mSecondB(Forward(aB)) + {} + + A& first() { return mFirstA; } + const A& first() const { return mFirstA; } + B& second() { return mSecondB; } + const B& second() const { return mSecondB; } + + void swap(PairHelper& aOther) + { + Swap(mFirstA, aOther.mFirstA); + Swap(mSecondB, aOther.mSecondB); + } + +private: + A mFirstA; + B mSecondB; +}; + +template +struct PairHelper : private B +{ +protected: + template + PairHelper(AArg&& aA, BArg&& aB) + : B(Forward(aB)), + mFirstA(Forward(aA)) + {} + + A& first() { return mFirstA; } + const A& first() const { return mFirstA; } + B& second() { return *this; } + const B& second() const { return *this; } + + void swap(PairHelper& aOther) + { + Swap(mFirstA, aOther.mFirstA); + Swap(static_cast(*this), static_cast(aOther)); + } + +private: + A mFirstA; +}; + +template +struct PairHelper : private A +{ +protected: + template + PairHelper(AArg&& aA, BArg&& aB) + : A(Forward(aA)), + mSecondB(Forward(aB)) + {} + + A& first() { return *this; } + const A& first() const { return *this; } + B& second() { return mSecondB; } + const B& second() const { return mSecondB; } + + void swap(PairHelper& aOther) + { + Swap(static_cast(*this), static_cast(aOther)); + Swap(mSecondB, aOther.mSecondB); + } + +private: + B mSecondB; +}; + +template +struct PairHelper : private A, private B +{ +protected: + template + PairHelper(AArg&& aA, BArg&& aB) + : A(Forward(aA)), + B(Forward(aB)) + {} + + A& first() { return static_cast(*this); } + const A& first() const { return static_cast(*this); } + B& second() { return static_cast(*this); } + const B& second() const { return static_cast(*this); } + + void swap(PairHelper& aOther) + { + Swap(static_cast(*this), static_cast(aOther)); + Swap(static_cast(*this), static_cast(aOther)); + } +}; + +} // namespace detail + +/** + * Pair is the logical concatenation of an instance of A with an instance B. + * Space is conserved when possible. Neither A nor B may be a final class. + * + * It's typically clearer to have individual A and B member fields. Except if + * you want the space-conserving qualities of Pair, you're probably better off + * not using this! + * + * No guarantees are provided about the memory layout of A and B, the order of + * initialization or destruction of A and B, and so on. (This is approximately + * required to optimize space usage.) The first/second names are merely + * conceptual! + */ +template +struct Pair + : private detail::PairHelper +{ + typedef typename detail::PairHelper Base; + +public: + template + Pair(AArg&& aA, BArg&& aB) + : Base(Forward(aA), Forward(aB)) + {} + + Pair(Pair&& aOther) + : Base(Move(aOther.first()), Move(aOther.second())) + { } + + Pair(const Pair& aOther) = default; + + Pair& operator=(Pair&& aOther) + { + MOZ_ASSERT(this != &aOther, "Self-moves are prohibited"); + + first() = Move(aOther.first()); + second() = Move(aOther.second()); + + return *this; + } + + Pair& operator=(const Pair& aOther) = default; + + /** The A instance. */ + using Base::first; + /** The B instance. */ + using Base::second; + + /** Swap this pair with another pair. */ + void swap(Pair& aOther) { Base::swap(aOther); } +}; + +template +void +Swap(Pair& aX, Pair& aY) +{ + aX.swap(aY); +} + +/** + * MakePair allows you to construct a Pair instance using type inference. A call + * like this: + * + * MakePair(Foo(), Bar()) + * + * will return a Pair. + */ +template +Pair::Type>::Type, + typename RemoveCV::Type>::Type> +MakePair(A&& aA, B&& aB) +{ + return + Pair::Type>::Type, + typename RemoveCV::Type>::Type>( + Forward(aA), + Forward(aB)); +} + +} // namespace mozilla + +#endif /* mozilla_Pair_h */ diff --git a/onlineupdate/source/update/inc/mozilla/UniquePtr.h b/onlineupdate/source/update/inc/mozilla/UniquePtr.h new file mode 100644 index 000000000000..d58ffe335c53 --- /dev/null +++ b/onlineupdate/source/update/inc/mozilla/UniquePtr.h @@ -0,0 +1,659 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Smart pointer managing sole ownership of a resource. */ + +#ifndef mozilla_UniquePtr_h +#define mozilla_UniquePtr_h + +#include "mozilla/Assertions.h" +#include "mozilla/Attributes.h" +#include "mozilla/Compiler.h" +#include "mozilla/Move.h" +#include "mozilla/Pair.h" +#include "mozilla/TypeTraits.h" + +namespace mozilla { + +template class DefaultDelete; +template> class UniquePtr; + +} // namespace mozilla + +namespace mozilla { + +/** + * UniquePtr is a smart pointer that wholly owns a resource. Ownership may be + * transferred out of a UniquePtr through explicit action, but otherwise the + * resource is destroyed when the UniquePtr is destroyed. + * + * UniquePtr is similar to C++98's std::auto_ptr, but it improves upon auto_ptr + * in one crucial way: it's impossible to copy a UniquePtr. Copying an auto_ptr + * obviously *can't* copy ownership of its singly-owned resource. So what + * happens if you try to copy one? Bizarrely, ownership is implicitly + * *transferred*, preserving single ownership but breaking code that assumes a + * copy of an object is identical to the original. (This is why auto_ptr is + * prohibited in STL containers.) + * + * UniquePtr solves this problem by being *movable* rather than copyable. + * Instead of passing a |UniquePtr u| directly to the constructor or assignment + * operator, you pass |Move(u)|. In doing so you indicate that you're *moving* + * ownership out of |u|, into the target of the construction/assignment. After + * the transfer completes, |u| contains |nullptr| and may be safely destroyed. + * This preserves single ownership but also allows UniquePtr to be moved by + * algorithms that have been made move-safe. (Note: if |u| is instead a + * temporary expression, don't use |Move()|: just pass the expression, because + * it's already move-ready. For more information see Move.h.) + * + * UniquePtr is also better than std::auto_ptr in that the deletion operation is + * customizable. An optional second template parameter specifies a class that + * (through its operator()(T*)) implements the desired deletion policy. If no + * policy is specified, mozilla::DefaultDelete is used -- which will either + * |delete| or |delete[]| the resource, depending whether the resource is an + * array. Custom deletion policies ideally should be empty classes (no member + * fields, no member fields in base classes, no virtual methods/inheritance), + * because then UniquePtr can be just as efficient as a raw pointer. + * + * Use of UniquePtr proceeds like so: + * + * UniquePtr g1; // initializes to nullptr + * g1.reset(new int); // switch resources using reset() + * g1 = nullptr; // clears g1, deletes the int + * + * UniquePtr g2(new int); // owns that int + * int* p = g2.release(); // g2 leaks its int -- still requires deletion + * delete p; // now freed + * + * struct S { int x; S(int x) : x(x) {} }; + * UniquePtr g3, g4(new S(5)); + * g3 = Move(g4); // g3 owns the S, g4 cleared + * S* p = g3.get(); // g3 still owns |p| + * assert(g3->x == 5); // operator-> works (if .get() != nullptr) + * assert((*g3).x == 5); // also operator* (again, if not cleared) + * Swap(g3, g4); // g4 now owns the S, g3 cleared + * g3.swap(g4); // g3 now owns the S, g4 cleared + * UniquePtr g5(Move(g3)); // g5 owns the S, g3 cleared + * g5.reset(); // deletes the S, g5 cleared + * + * struct FreePolicy { void operator()(void* p) { free(p); } }; + * UniquePtr g6(static_cast(malloc(sizeof(int)))); + * int* ptr = g6.get(); + * g6 = nullptr; // calls free(ptr) + * + * Now, carefully note a few things you *can't* do: + * + * UniquePtr b1; + * b1 = new int; // BAD: can only assign another UniquePtr + * int* ptr = b1; // BAD: no auto-conversion to pointer, use get() + * + * UniquePtr b2(b1); // BAD: can't copy a UniquePtr + * UniquePtr b3 = b1; // BAD: can't copy-assign a UniquePtr + * + * (Note that changing a UniquePtr to store a direct |new| expression is + * permitted, but usually you should use MakeUnique, defined at the end of this + * header.) + * + * A few miscellaneous notes: + * + * UniquePtr, when not instantiated for an array type, can be move-constructed + * and move-assigned, not only from itself but from "derived" UniquePtr + * instantiations where U converts to T and E converts to D. If you want to use + * this, you're going to have to specify a deletion policy for both UniquePtr + * instantations, and T pretty much has to have a virtual destructor. In other + * words, this doesn't work: + * + * struct Base { virtual ~Base() {} }; + * struct Derived : Base {}; + * + * UniquePtr b1; + * // BAD: DefaultDelete and DefaultDelete don't interconvert + * UniquePtr d1(Move(b)); + * + * UniquePtr b2; + * UniquePtr> d2(Move(b2)); // okay + * + * UniquePtr is specialized for array types. Specializing with an array type + * creates a smart-pointer version of that array -- not a pointer to such an + * array. + * + * UniquePtr arr(new int[5]); + * arr[0] = 4; + * + * What else is different? Deletion of course uses |delete[]|. An operator[] + * is provided. Functionality that doesn't make sense for arrays is removed. + * The constructors and mutating methods only accept array pointers (not T*, U* + * that converts to T*, or UniquePtr or UniquePtr) or |nullptr|. + * + * It's perfectly okay to return a UniquePtr from a method to assure the related + * resource is properly deleted. You'll need to use |Move()| when returning a + * local UniquePtr. Otherwise you can return |nullptr|, or you can return + * |UniquePtr(ptr)|. + * + * UniquePtr will commonly be a member of a class, with lifetime equivalent to + * that of that class. If you want to expose the related resource, you could + * expose a raw pointer via |get()|, but ownership of a raw pointer is + * inherently unclear. So it's better to expose a |const UniquePtr&| instead. + * This prohibits mutation but still allows use of |get()| when needed (but + * operator-> is preferred). Of course, you can only use this smart pointer as + * long as the enclosing class instance remains live -- no different than if you + * exposed the |get()| raw pointer. + * + * To pass a UniquePtr-managed resource as a pointer, use a |const UniquePtr&| + * argument. To specify an inout parameter (where the method may or may not + * take ownership of the resource, or reset it), or to specify an out parameter + * (where simply returning a |UniquePtr| isn't possible), use a |UniquePtr&| + * argument. To unconditionally transfer ownership of a UniquePtr + * into a method, use a |UniquePtr| argument. To conditionally transfer + * ownership of a resource into a method, should the method want it, use a + * |UniquePtr&&| argument. + */ +template +class UniquePtr +{ +public: + typedef T* Pointer; + typedef T ElementType; + typedef D DeleterType; + +private: + Pair mTuple; + + Pointer& ptr() { return mTuple.first(); } + const Pointer& ptr() const { return mTuple.first(); } + + DeleterType& del() { return mTuple.second(); } + const DeleterType& del() const { return mTuple.second(); } + +public: + /** + * Construct a UniquePtr containing |nullptr|. + */ + MOZ_CONSTEXPR UniquePtr() + : mTuple(static_cast(nullptr), DeleterType()) + { + static_assert(!IsPointer::value, "must provide a deleter instance"); + static_assert(!IsReference::value, "must provide a deleter instance"); + } + + /** + * Construct a UniquePtr containing |aPtr|. + */ + explicit UniquePtr(Pointer aPtr) + : mTuple(aPtr, DeleterType()) + { + static_assert(!IsPointer::value, "must provide a deleter instance"); + static_assert(!IsReference::value, "must provide a deleter instance"); + } + + UniquePtr(Pointer aPtr, + typename Conditional::value, + D, + const D&>::Type aD1) + : mTuple(aPtr, aD1) + {} + + // If you encounter an error with MSVC10 about RemoveReference below, along + // the lines that "more than one partial specialization matches the template + // argument list": don't use UniquePtr! Ideally + // you should make deletion use the same function every time, using a + // deleter policy: + // + // // BAD, won't compile with MSVC10, deleter doesn't need to be a + // // variable at all + // typedef void (&FreeSignature)(void*); + // UniquePtr ptr((int*) malloc(sizeof(int)), free); + // + // // GOOD, compiles with MSVC10, deletion behavior statically known and + // // optimizable + // struct DeleteByFreeing + // { + // void operator()(void* aPtr) { free(aPtr); } + // }; + // + // If deletion really, truly, must be a variable: you might be able to work + // around this with a deleter class that contains the function reference. + // But this workaround is untried and untested, because variable deletion + // behavior really isn't something you should use. + UniquePtr(Pointer aPtr, + typename RemoveReference::Type&& aD2) + : mTuple(aPtr, Move(aD2)) + { + static_assert(!IsReference::value, + "rvalue deleter can't be stored by reference"); + } + + UniquePtr(UniquePtr&& aOther) + : mTuple(aOther.release(), Forward(aOther.getDeleter())) + {} + + MOZ_IMPLICIT + UniquePtr(decltype(nullptr)) + : mTuple(nullptr, DeleterType()) + { + static_assert(!IsPointer::value, "must provide a deleter instance"); + static_assert(!IsReference::value, "must provide a deleter instance"); + } + + template + UniquePtr(UniquePtr&& aOther, + typename EnableIf::Pointer, + Pointer>::value && + !IsArray::value && + (IsReference::value + ? IsSame::value + : IsConvertible::value), + int>::Type aDummy = 0) + : mTuple(aOther.release(), Forward(aOther.getDeleter())) + { + } + + ~UniquePtr() { reset(nullptr); } + + UniquePtr& operator=(UniquePtr&& aOther) + { + reset(aOther.release()); + getDeleter() = Forward(aOther.getDeleter()); + return *this; + } + + template + UniquePtr& operator=(UniquePtr&& aOther) + { + static_assert(IsConvertible::Pointer, + Pointer>::value, + "incompatible UniquePtr pointees"); + static_assert(!IsArray::value, + "can't assign from UniquePtr holding an array"); + + reset(aOther.release()); + getDeleter() = Forward(aOther.getDeleter()); + return *this; + } + + UniquePtr& operator=(decltype(nullptr)) + { + reset(nullptr); + return *this; + } + + T& operator*() const { return *get(); } + Pointer operator->() const + { + MOZ_ASSERT(get(), "dereferencing a UniquePtr containing nullptr"); + return get(); + } + + explicit operator bool() const { return get() != nullptr; } + + Pointer get() const { return ptr(); } + + DeleterType& getDeleter() { return del(); } + const DeleterType& getDeleter() const { return del(); } + + Pointer release() + { + Pointer p = ptr(); + ptr() = nullptr; + return p; + } + + void reset(Pointer aPtr = Pointer()) + { + Pointer old = ptr(); + ptr() = aPtr; + if (old != nullptr) { + getDeleter()(old); + } + } + + void swap(UniquePtr& aOther) + { + mTuple.swap(aOther.mTuple); + } + +private: + UniquePtr(const UniquePtr& aOther) = delete; // construct using Move()! + void operator=(const UniquePtr& aOther) = delete; // assign using Move()! +}; + +// In case you didn't read the comment by the main definition (you should!): the +// UniquePtr specialization exists to manage array pointers. It deletes +// such pointers using delete[], it will reject construction and modification +// attempts using U* or U[]. Otherwise it works like the normal UniquePtr. +template +class UniquePtr +{ +public: + typedef T* Pointer; + typedef T ElementType; + typedef D DeleterType; + +private: + Pair mTuple; + +public: + /** + * Construct a UniquePtr containing nullptr. + */ + MOZ_CONSTEXPR UniquePtr() + : mTuple(static_cast(nullptr), DeleterType()) + { + static_assert(!IsPointer::value, "must provide a deleter instance"); + static_assert(!IsReference::value, "must provide a deleter instance"); + } + + /** + * Construct a UniquePtr containing |aPtr|. + */ + explicit UniquePtr(Pointer aPtr) + : mTuple(aPtr, DeleterType()) + { + static_assert(!IsPointer::value, "must provide a deleter instance"); + static_assert(!IsReference::value, "must provide a deleter instance"); + } + +private: + // delete[] knows how to handle *only* an array of a single class type. For + // delete[] to work correctly, it must know the size of each element, the + // fields and base classes of each element requiring destruction, and so on. + // So forbid all overloads which would end up invoking delete[] on a pointer + // of the wrong type. + template + UniquePtr(U&& aU, + typename EnableIf::value && + IsConvertible::value, + int>::Type aDummy = 0) + = delete; + +public: + UniquePtr(Pointer aPtr, + typename Conditional::value, + D, + const D&>::Type aD1) + : mTuple(aPtr, aD1) + {} + + // If you encounter an error with MSVC10 about RemoveReference below, along + // the lines that "more than one partial specialization matches the template + // argument list": don't use UniquePtr! See the + // comment by this constructor in the non-T[] specialization above. + UniquePtr(Pointer aPtr, + typename RemoveReference::Type&& aD2) + : mTuple(aPtr, Move(aD2)) + { + static_assert(!IsReference::value, + "rvalue deleter can't be stored by reference"); + } + +private: + // Forbidden for the same reasons as stated above. + template + UniquePtr(U&& aU, V&& aV, + typename EnableIf::value && + IsConvertible::value, + int>::Type aDummy = 0) + = delete; + +public: + UniquePtr(UniquePtr&& aOther) + : mTuple(aOther.release(), Forward(aOther.getDeleter())) + {} + + MOZ_IMPLICIT + UniquePtr(decltype(nullptr)) + : mTuple(nullptr, DeleterType()) + { + static_assert(!IsPointer::value, "must provide a deleter instance"); + static_assert(!IsReference::value, "must provide a deleter instance"); + } + + ~UniquePtr() { reset(nullptr); } + + UniquePtr& operator=(UniquePtr&& aOther) + { + reset(aOther.release()); + getDeleter() = Forward(aOther.getDeleter()); + return *this; + } + + UniquePtr& operator=(decltype(nullptr)) + { + reset(); + return *this; + } + + explicit operator bool() const { return get() != nullptr; } + + T& operator[](decltype(sizeof(int)) aIndex) const { return get()[aIndex]; } + Pointer get() const { return mTuple.first(); } + + DeleterType& getDeleter() { return mTuple.second(); } + const DeleterType& getDeleter() const { return mTuple.second(); } + + Pointer release() + { + Pointer p = mTuple.first(); + mTuple.first() = nullptr; + return p; + } + + void reset(Pointer aPtr = Pointer()) + { + Pointer old = mTuple.first(); + mTuple.first() = aPtr; + if (old != nullptr) { + mTuple.second()(old); + } + } + + void reset(decltype(nullptr)) + { + Pointer old = mTuple.first(); + mTuple.first() = nullptr; + if (old != nullptr) { + mTuple.second()(old); + } + } + +private: + template + void reset(U) = delete; + +public: + void swap(UniquePtr& aOther) { mTuple.swap(aOther.mTuple); } + +private: + UniquePtr(const UniquePtr& aOther) = delete; // construct using Move()! + void operator=(const UniquePtr& aOther) = delete; // assign using Move()! +}; + +/** A default deletion policy using plain old operator delete. */ +template +class DefaultDelete +{ +public: + MOZ_CONSTEXPR DefaultDelete() {} + + template + DefaultDelete(const DefaultDelete& aOther, + typename EnableIf::value, + int>::Type aDummy = 0) + {} + + void operator()(T* aPtr) const + { + static_assert(sizeof(T) > 0, "T must be complete"); + delete aPtr; + } +}; + +/** A default deletion policy using operator delete[]. */ +template +class DefaultDelete +{ +public: + MOZ_CONSTEXPR DefaultDelete() {} + + void operator()(T* aPtr) const + { + static_assert(sizeof(T) > 0, "T must be complete"); + delete[] aPtr; + } + +private: + template + void operator()(U* aPtr) const = delete; +}; + +template +void +Swap(UniquePtr& aX, UniquePtr& aY) +{ + aX.swap(aY); +} + +template +bool +operator==(const UniquePtr& aX, const UniquePtr& aY) +{ + return aX.get() == aY.get(); +} + +template +bool +operator!=(const UniquePtr& aX, const UniquePtr& aY) +{ + return aX.get() != aY.get(); +} + +template +bool +operator==(const UniquePtr& aX, decltype(nullptr)) +{ + return !aX; +} + +template +bool +operator==(decltype(nullptr), const UniquePtr& aX) +{ + return !aX; +} + +template +bool +operator!=(const UniquePtr& aX, decltype(nullptr)) +{ + return bool(aX); +} + +template +bool +operator!=(decltype(nullptr), const UniquePtr& aX) +{ + return bool(aX); +} + +// No operator<, operator>, operator<=, operator>= for now because simplicity. + +namespace detail { + +template +struct UniqueSelector +{ + typedef UniquePtr SingleObject; +}; + +template +struct UniqueSelector +{ + typedef UniquePtr UnknownBound; +}; + +template +struct UniqueSelector +{ + typedef UniquePtr KnownBound; +}; + +} // namespace detail + +/** + * MakeUnique is a helper function for allocating new'd objects and arrays, + * returning a UniquePtr containing the resulting pointer. The semantics of + * MakeUnique(...) are as follows. + * + * If Type is an array T[n]: + * Disallowed, deleted, no overload for you! + * If Type is an array T[]: + * MakeUnique(size_t) is the only valid overload. The pointer returned + * is as if by |new T[n]()|, which value-initializes each element. (If T + * isn't a class type, this will zero each element. If T is a class type, + * then roughly speaking, each element will be constructed using its default + * constructor. See C++11 [dcl.init]p7 for the full gory details.) + * If Type is non-array T: + * The arguments passed to MakeUnique(...) are forwarded into a + * |new T(...)| call, initializing the T as would happen if executing + * |T(...)|. + * + * There are various benefits to using MakeUnique instead of |new| expressions. + * + * First, MakeUnique eliminates use of |new| from code entirely. If objects are + * only created through UniquePtr, then (assuming all explicit release() calls + * are safe, including transitively, and no type-safety casting funniness) + * correctly maintained ownership of the UniquePtr guarantees no leaks are + * possible. (This pays off best if a class is only ever created through a + * factory method on the class, using a private constructor.) + * + * Second, initializing a UniquePtr using a |new| expression requires repeating + * the name of the new'd type, whereas MakeUnique in concert with the |auto| + * keyword names it only once: + * + * UniquePtr ptr1(new char()); // repetitive + * auto ptr2 = MakeUnique(); // shorter + * + * Of course this assumes the reader understands the operation MakeUnique + * performs. In the long run this is probably a reasonable assumption. In the + * short run you'll have to use your judgment about what readers can be expected + * to know, or to quickly look up. + * + * Third, a call to MakeUnique can be assigned directly to a UniquePtr. In + * contrast you can't assign a pointer into a UniquePtr without using the + * cumbersome reset(). + * + * UniquePtr p; + * p = new char; // ERROR + * p.reset(new char); // works, but fugly + * p = MakeUnique(); // preferred + * + * (And third, although not relevant to Mozilla: MakeUnique is exception-safe. + * An exception thrown after |new T| succeeds will leak that memory, unless the + * pointer is assigned to an object that will manage its ownership. UniquePtr + * ably serves this function.) + */ + +template +typename detail::UniqueSelector::SingleObject +MakeUnique(Args&&... aArgs) +{ + return UniquePtr(new T(Forward(aArgs)...)); +} + +template +typename detail::UniqueSelector::UnknownBound +MakeUnique(decltype(sizeof(int)) aN) +{ + typedef typename RemoveExtent::Type ArrayType; + return UniquePtr(new ArrayType[aN]()); +} + +template +typename detail::UniqueSelector::KnownBound +MakeUnique(Args&&... aArgs) = delete; + +} // namespace mozilla + +#endif /* mozilla_UniquePtr_h */ diff --git a/onlineupdate/source/update/inc/nsAutoRef.h b/onlineupdate/source/update/inc/nsAutoRef.h new file mode 100644 index 000000000000..a159f5954e96 --- /dev/null +++ b/onlineupdate/source/update/inc/nsAutoRef.h @@ -0,0 +1,670 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsAutoRef_h_ +#define nsAutoRef_h_ + +#include "mozilla/Attributes.h" + +template class nsSimpleRef; +template class nsAutoRefBase; +template class nsReturnRef; +template class nsReturningRef; + +/** + * template class nsAutoRef + * + * A class that holds a handle to a resource that must be released. + * No reference is added on construction. + * + * No copy constructor nor copy assignment operators are available, so the + * resource will be held until released on destruction or explicitly + * |reset()| or transferred through provided methods. + * + * The publicly available methods are the public methods on this class and its + * public base classes |nsAutoRefBase| and |nsSimpleRef|. + * + * For ref-counted resources see also |nsCountedRef|. + * For function return values see |nsReturnRef|. + * + * For each class |T|, |nsAutoRefTraits| or |nsSimpleRef| must be + * specialized to use |nsAutoRef| and |nsCountedRef|. + * + * @param T A class identifying the type of reference held by the + * |nsAutoRef| and the unique set methods for managing references + * to the resource (defined by |nsAutoRefTraits| or + * |nsSimpleRef|). + * + * Often this is the class representing the resource. Sometimes a + * new possibly-incomplete class may need to be declared. + * + * + * Example: An Automatically closing file descriptor + * + * // References that are simple integral types (as file-descriptors are) + * // usually need a new class to represent the resource and how to handle its + * // references. + * class nsRawFD; + * + * // Specializing nsAutoRefTraits describes how to manage file + * // descriptors, so that nsAutoRef provides automatic closing of + * // its file descriptor on destruction. + * template <> + * class nsAutoRefTraits { + * public: + * // The file descriptor is held in an int. + * typedef int RawRef; + * // -1 means that there is no file associated with the handle. + * static int Void() { return -1; } + * // The file associated with a file descriptor is released with close(). + * static void Release(RawRef aFD) { close(aFD); } + * }; + * + * // A function returning a file descriptor that must be closed. + * nsReturnRef get_file(const char *filename) { + * // Constructing from a raw file descriptor assumes ownership. + * nsAutoRef fd(open(filename, O_RDONLY)); + * fcntl(fd, F_SETFD, FD_CLOEXEC); + * return fd.out(); + * } + * + * void f() { + * unsigned char buf[1024]; + * + * // Hold a file descriptor for /etc/hosts in fd1. + * nsAutoRef fd1(get_file("/etc/hosts")); + * + * nsAutoRef fd2; + * fd2.steal(fd1); // fd2 takes the file descriptor from fd1 + * ssize_t count = read(fd1, buf, 1024); // error fd1 has no file + * count = read(fd2, buf, 1024); // reads from /etc/hosts + * + * // If the file descriptor is not stored then it is closed. + * get_file("/etc/login.defs"); // login.defs is closed + * + * // Now use fd1 to hold a file descriptor for /etc/passwd. + * fd1 = get_file("/etc/passwd"); + * + * // The nsAutoRef can give up the file descriptor if explicitly + * // instructed, but the caller must then ensure that the file is closed. + * int rawfd = fd1.disown(); + * + * // Assume ownership of another file descriptor. + * fd1.own(open("/proc/1/maps"); + * + * // On destruction, fd1 closes /proc/1/maps and fd2 closes /etc/hosts, + * // but /etc/passwd is not closed. + * } + * + */ + + +template +class nsAutoRef : public nsAutoRefBase +{ +protected: + typedef nsAutoRef ThisClass; + typedef nsAutoRefBase BaseClass; + typedef nsSimpleRef SimpleRef; + typedef typename BaseClass::RawRefOnly RawRefOnly; + typedef typename BaseClass::LocalSimpleRef LocalSimpleRef; + +public: + nsAutoRef() + { + } + + // Explicit construction is required so as not to risk unintentionally + // releasing the resource associated with a raw ref. + explicit nsAutoRef(RawRefOnly aRefToRelease) + : BaseClass(aRefToRelease) + { + } + + // Construction from a nsReturnRef function return value, which expects + // to give up ownership, transfers ownership. + // (nsReturnRef is converted to const nsReturningRef.) + explicit nsAutoRef(const nsReturningRef& aReturning) + : BaseClass(aReturning) + { + } + + // The only assignment operator provided is for transferring from an + // nsReturnRef smart reference, which expects to pass its ownership to + // another object. + // + // With raw references and other smart references, the type of the lhs and + // its taking and releasing nature is often not obvious from an assignment + // statement. Assignment from a raw ptr especially is not normally + // expected to release the reference. + // + // Use |steal| for taking ownership from other smart refs. + // + // For raw references, use |own| to indicate intention to have the + // resource released. + // + // Or, to create another owner of the same reference, use an nsCountedRef. + + ThisClass& operator=(const nsReturningRef& aReturning) + { + BaseClass::steal(aReturning.mReturnRef); + return *this; + } + + // Conversion to a raw reference allow the nsAutoRef to often be used + // like a raw reference. + operator typename SimpleRef::RawRef() const + { + return this->get(); + } + + // Transfer ownership from another smart reference. + void steal(ThisClass& aOtherRef) + { + BaseClass::steal(aOtherRef); + } + + // Assume ownership of a raw ref. + // + // |own| has similar function to |steal|, and is useful for receiving + // ownership from a return value of a function. It is named differently + // because |own| requires more care to ensure that the function intends to + // give away ownership, and so that |steal| can be safely used, knowing + // that it won't steal ownership from any methods returning raw ptrs to + // data owned by a foreign object. + void own(RawRefOnly aRefToRelease) + { + BaseClass::own(aRefToRelease); + } + + // Exchange ownership with |aOther| + void swap(ThisClass& aOther) + { + LocalSimpleRef temp; + temp.SimpleRef::operator=(*this); + SimpleRef::operator=(aOther); + aOther.SimpleRef::operator=(temp); + } + + // Release the reference now. + void reset() + { + this->SafeRelease(); + LocalSimpleRef empty; + SimpleRef::operator=(empty); + } + + // Pass out the reference for a function return values. + nsReturnRef out() + { + return nsReturnRef(this->disown()); + } + + // operator->() and disown() are provided by nsAutoRefBase. + // The default nsSimpleRef provides get(). + +private: + // No copy constructor + explicit nsAutoRef(ThisClass& aRefToSteal); +}; + +/** + * template class nsCountedRef + * + * A class that creates (adds) a new reference to a resource on construction + * or assignment and releases on destruction. + * + * This class is similar to nsAutoRef and inherits its methods, but also + * provides copy construction and assignment operators that enable more than + * one concurrent reference to the same resource. + * + * Specialize |nsAutoRefTraits| or |nsSimpleRef| to use this. This + * class assumes that the resource itself counts references and so can only be + * used when |T| represents a reference-counting resource. + */ + +template +class nsCountedRef : public nsAutoRef +{ +protected: + typedef nsCountedRef ThisClass; + typedef nsAutoRef BaseClass; + typedef nsSimpleRef SimpleRef; + typedef typename BaseClass::RawRef RawRef; + +public: + nsCountedRef() + { + } + + // Construction and assignment from a another nsCountedRef + // or a raw ref copies and increments the ref count. + nsCountedRef(const ThisClass& aRefToCopy) + { + SimpleRef::operator=(aRefToCopy); + SafeAddRef(); + } + ThisClass& operator=(const ThisClass& aRefToCopy) + { + if (this == &aRefToCopy) { + return *this; + } + + this->SafeRelease(); + SimpleRef::operator=(aRefToCopy); + SafeAddRef(); + return *this; + } + + // Implicit conversion from another smart ref argument (to a raw ref) is + // accepted here because construction and assignment safely creates a new + // reference without interfering with the reference to copy. + explicit nsCountedRef(RawRef aRefToCopy) + : BaseClass(aRefToCopy) + { + SafeAddRef(); + } + ThisClass& operator=(RawRef aRefToCopy) + { + this->own(aRefToCopy); + SafeAddRef(); + return *this; + } + + // Construction and assignment from an nsReturnRef function return value, + // which expects to give up ownership, transfers ownership. + explicit nsCountedRef(const nsReturningRef& aReturning) + : BaseClass(aReturning) + { + } + ThisClass& operator=(const nsReturningRef& aReturning) + { + BaseClass::operator=(aReturning); + return *this; + } + +protected: + // Increase the reference count if there is a resource. + void SafeAddRef() + { + if (this->HaveResource()) { + this->AddRef(this->get()); + } + } +}; + +/** + * template class nsReturnRef + * + * A type for function return values that hold a reference to a resource that + * must be released. See also |nsAutoRef::out()|. + */ + +template +class nsReturnRef : public nsAutoRefBase +{ +protected: + typedef nsAutoRefBase BaseClass; + typedef typename BaseClass::RawRefOnly RawRefOnly; + +public: + // For constructing a return value with no resource + nsReturnRef() + { + } + + // For returning a smart reference from a raw reference that must be + // released. Explicit construction is required so as not to risk + // unintentionally releasing the resource associated with a raw ref. + MOZ_IMPLICIT nsReturnRef(RawRefOnly aRefToRelease) + : BaseClass(aRefToRelease) + { + } + + // Copy construction transfers ownership + nsReturnRef(nsReturnRef& aRefToSteal) + : BaseClass(aRefToSteal) + { + } + + MOZ_IMPLICIT nsReturnRef(const nsReturningRef& aReturning) + : BaseClass(aReturning) + { + } + + // Conversion to a temporary (const) object referring to this object so + // that the reference may be passed from a function return value + // (temporary) to another smart reference. There is no need to use this + // explicitly. Simply assign a nsReturnRef function return value to a + // smart reference. + operator nsReturningRef() + { + return nsReturningRef(*this); + } + + // No conversion to RawRef operator is provided on nsReturnRef, to ensure + // that the return value is not carelessly assigned to a raw ptr (and the + // resource then released). If passing to a function that takes a raw + // ptr, use get or disown as appropriate. +}; + +/** + * template class nsReturningRef + * + * A class to allow ownership to be transferred from nsReturnRef function + * return values. + * + * It should not be necessary for clients to reference this + * class directly. Simply pass an nsReturnRef to a parameter taking an + * |nsReturningRef|. + * + * The conversion operator on nsReturnRef constructs a temporary wrapper of + * class nsReturningRef around a non-const reference to the nsReturnRef. + * The wrapper can then be passed as an rvalue parameter. + */ + +template +class nsReturningRef +{ +private: + friend class nsReturnRef; + + explicit nsReturningRef(nsReturnRef& aReturnRef) + : mReturnRef(aReturnRef) + { + } +public: + nsReturnRef& mReturnRef; +}; + +/** + * template class nsAutoRefTraits + * + * A class describing traits of references managed by the default + * |nsSimpleRef| implementation and thus |nsAutoRef| and |nsCountedRef|. + * The default |nsSimpleRef is suitable for resources with handles that + * have a void value. (If there is no such void value for a handle, + * specialize |nsSimpleRef|.) + * + * Specializations must be provided for each class |T| according to the + * following pattern: + * + * // The template parameter |T| should be a class such that the set of fields + * // in class nsAutoRefTraits is unique for class |T|. Usually the + * // resource object class is sufficient. For handles that are simple + * // integral typedefs, a new unique possibly-incomplete class may need to be + * // declared. + * + * template <> + * class nsAutoRefTraits + * { + * // Specializations must provide a typedef for RawRef, describing the + * // type of the handle to the resource. + * typedef RawRef; + * + * // Specializations should define Void(), a function returning a value + * // suitable for a handle that does not have an associated resource. + * // + * // The return type must be a suitable as the parameter to a RawRef + * // constructor and operator==. + * // + * // If this method is not accessible then some limited nsAutoRef + * // functionality will still be available, but the default constructor, + * // |reset|, and most transfer of ownership methods will not be available. + * static Void(); + * + * // Specializations must define Release() to properly finalize the + * // handle to a non-void custom-deleted or reference-counted resource. + * static void Release(RawRef aRawRef); + * + * // For reference-counted resources, if |nsCountedRef| is to be used, + * // specializations must define AddRef to increment the reference count + * // held by a non-void handle. + * // (AddRef() is not necessary for |nsAutoRef|.) + * static void AddRef(RawRef aRawRef); + * }; + * + * See nsPointerRefTraits for example specializations for simple pointer + * references. See nsAutoRef for an example specialization for a non-pointer + * reference. + */ + +template class nsAutoRefTraits; + +/** + * template class nsPointerRefTraits + * + * A convenience class useful as a base class for specializations of + * |nsAutoRefTraits| where the handle to the resource is a pointer to |T|. + * By inheriting from this class, definitions of only Release(RawRef) and + * possibly AddRef(RawRef) need to be added. + * + * Examples of use: + * + * template <> + * class nsAutoRefTraits : public nsPointerRefTraits + * { + * public: + * static void Release(PRFileDesc *ptr) { PR_Close(ptr); } + * }; + * + * template <> + * class nsAutoRefTraits : public nsPointerRefTraits + * { + * public: + * static void Release(FcPattern *ptr) { FcPatternDestroy(ptr); } + * static void AddRef(FcPattern *ptr) { FcPatternReference(ptr); } + * }; + */ + +template +class nsPointerRefTraits +{ +public: + // The handle is a pointer to T. + typedef T* RawRef; + // A nullptr does not have a resource. + static RawRef Void() + { + return nullptr; + } +}; + +/** + * template class nsSimpleRef + * + * Constructs a non-smart reference, and provides methods to test whether + * there is an associated resource and (if so) get its raw handle. + * + * A default implementation is suitable for resources with handles that have a + * void value. This is not intended for direct use but used by |nsAutoRef| + * and thus |nsCountedRef|. + * + * Specialize this class if there is no particular void value for the resource + * handle. A specialized implementation must also provide Release(RawRef), + * and, if |nsCountedRef| is required, AddRef(RawRef), as described in + * nsAutoRefTraits. + */ + +template +class nsSimpleRef : protected nsAutoRefTraits +{ +protected: + // The default implementation uses nsAutoRefTrait. + // Specializations need not define this typedef. + typedef nsAutoRefTraits Traits; + // The type of the handle to the resource. + // A specialization must provide a typedef for RawRef. + typedef typename Traits::RawRef RawRef; + + // Construct with no resource. + // + // If this constructor is not accessible then some limited nsAutoRef + // functionality will still be available, but the default constructor, + // |reset|, and most transfer of ownership methods will not be available. + nsSimpleRef() + : mRawRef(Traits::Void()) + { + } + // Construct with a handle to a resource. + // A specialization must provide this. + explicit nsSimpleRef(RawRef aRawRef) + : mRawRef(aRawRef) + { + } + + // Test whether there is an associated resource. A specialization must + // provide this. The function is permitted to always return true if the + // default constructor is not accessible, or if Release (and AddRef) can + // deal with void handles. + bool HaveResource() const + { + return mRawRef != Traits::Void(); + } + +public: + // A specialization must provide get() or loose some functionality. This + // is inherited by derived classes and the specialization may choose + // whether it is public or protected. + RawRef get() const + { + return mRawRef; + } + +private: + RawRef mRawRef; +}; + + +/** + * template class nsAutoRefBase + * + * Internal base class for |nsAutoRef| and |nsReturnRef|. + * Adds release on destruction to a |nsSimpleRef|. + */ + +template +class nsAutoRefBase : public nsSimpleRef +{ +protected: + typedef nsAutoRefBase ThisClass; + typedef nsSimpleRef SimpleRef; + typedef typename SimpleRef::RawRef RawRef; + + nsAutoRefBase() + { + } + + // A type for parameters that should be passed a raw ref but should not + // accept implicit conversions (from another smart ref). (The only + // conversion to this type is from a raw ref so only raw refs will be + // accepted.) + class RawRefOnly + { + public: + MOZ_IMPLICIT RawRefOnly(RawRef aRawRef) + : mRawRef(aRawRef) + { + } + operator RawRef() const + { + return mRawRef; + } + private: + RawRef mRawRef; + }; + + // Construction from a raw ref assumes ownership + explicit nsAutoRefBase(RawRefOnly aRefToRelease) + : SimpleRef(aRefToRelease) + { + } + + // Constructors that steal ownership + explicit nsAutoRefBase(ThisClass& aRefToSteal) + : SimpleRef(aRefToSteal.disown()) + { + } + explicit nsAutoRefBase(const nsReturningRef& aReturning) + : SimpleRef(aReturning.mReturnRef.disown()) + { + } + + ~nsAutoRefBase() + { + SafeRelease(); + } + + // An internal class providing access to protected nsSimpleRef + // constructors for construction of temporary simple references (that are + // not ThisClass). + class LocalSimpleRef : public SimpleRef + { + public: + LocalSimpleRef() + { + } + explicit LocalSimpleRef(RawRef aRawRef) + : SimpleRef(aRawRef) + { + } + }; + +private: + ThisClass& operator=(const ThisClass& aSmartRef) = delete; + +public: + RawRef operator->() const + { + return this->get(); + } + + // Transfer ownership to a raw reference. + // + // THE CALLER MUST ENSURE THAT THE REFERENCE IS EXPLICITLY RELEASED. + // + // Is this really what you want to use? Using this removes any guarantee + // of release. Use nsAutoRef::out() for return values, or an + // nsAutoRef modifiable lvalue for an out parameter. Use disown() when + // the reference must be stored in a POD type object, such as may be + // preferred for a namespace-scope object with static storage duration, + // for example. + RawRef disown() + { + RawRef temp = this->get(); + LocalSimpleRef empty; + SimpleRef::operator=(empty); + return temp; + } + +protected: + // steal and own are protected because they make no sense on nsReturnRef, + // but steal is implemented on this class for access to aOtherRef.disown() + // when aOtherRef is an nsReturnRef; + + // Transfer ownership from another smart reference. + void steal(ThisClass& aOtherRef) + { + own(aOtherRef.disown()); + } + // Assume ownership of a raw ref. + void own(RawRefOnly aRefToRelease) + { + SafeRelease(); + LocalSimpleRef ref(aRefToRelease); + SimpleRef::operator=(ref); + } + + // Release a resource if there is one. + void SafeRelease() + { + if (this->HaveResource()) { + this->Release(this->get()); + } + } +}; + +#endif // !defined(nsAutoRef_h_) diff --git a/onlineupdate/source/update/inc/nsWindowsHelpers.h b/onlineupdate/source/update/inc/nsWindowsHelpers.h new file mode 100644 index 000000000000..c9284292691a --- /dev/null +++ b/onlineupdate/source/update/inc/nsWindowsHelpers.h @@ -0,0 +1,159 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsWindowsHelpers_h +#define nsWindowsHelpers_h + +#include +#include "nsAutoRef.h" + +// ---------------------------------------------------------------------------- +// Critical Section helper class +// ---------------------------------------------------------------------------- + +class AutoCriticalSection +{ +public: + AutoCriticalSection(LPCRITICAL_SECTION aSection) + : mSection(aSection) + { + ::EnterCriticalSection(mSection); + } + ~AutoCriticalSection() + { + ::LeaveCriticalSection(mSection); + } +private: + LPCRITICAL_SECTION mSection; +}; + +template<> +class nsAutoRefTraits +{ +public: + typedef HKEY RawRef; + static HKEY Void() + { + return nullptr; + } + + static void Release(RawRef aFD) + { + if (aFD != Void()) { + RegCloseKey(aFD); + } + } +}; + +template<> +class nsAutoRefTraits +{ +public: + typedef SC_HANDLE RawRef; + static SC_HANDLE Void() + { + return nullptr; + } + + static void Release(RawRef aFD) + { + if (aFD != Void()) { + CloseServiceHandle(aFD); + } + } +}; + +template<> +class nsSimpleRef +{ +protected: + typedef HANDLE RawRef; + + nsSimpleRef() : mRawRef(nullptr) + { + } + + nsSimpleRef(RawRef aRawRef) : mRawRef(aRawRef) + { + } + + bool HaveResource() const + { + return mRawRef && mRawRef != INVALID_HANDLE_VALUE; + } + +public: + RawRef get() const + { + return mRawRef; + } + + static void Release(RawRef aRawRef) + { + if (aRawRef && aRawRef != INVALID_HANDLE_VALUE) { + CloseHandle(aRawRef); + } + } + RawRef mRawRef; +}; + + +template<> +class nsAutoRefTraits +{ +public: + typedef HMODULE RawRef; + static RawRef Void() + { + return nullptr; + } + + static void Release(RawRef aFD) + { + if (aFD != Void()) { + FreeLibrary(aFD); + } + } +}; + +typedef nsAutoRef nsAutoRegKey; +typedef nsAutoRef nsAutoServiceHandle; +typedef nsAutoRef nsAutoHandle; +typedef nsAutoRef nsModuleHandle; + +namespace { + +HMODULE inline +LoadLibrarySystem32(LPCWSTR aModule) +{ + WCHAR systemPath[MAX_PATH + 1] = { L'\0' }; + + // If GetSystemPath fails we accept that we'll load the DLLs from the + // normal search path. + GetSystemDirectoryW(systemPath, MAX_PATH + 1); + size_t systemDirLen = wcslen(systemPath); + + // Make the system directory path terminate with a slash + if (systemDirLen && systemPath[systemDirLen - 1] != L'\\') { + systemPath[systemDirLen] = L'\\'; + ++systemDirLen; + // No need to re-nullptr terminate + } + + size_t fileLen = wcslen(aModule); + wcsncpy(systemPath + systemDirLen, aModule, + MAX_PATH - systemDirLen); + if (systemDirLen + fileLen <= MAX_PATH) { + systemPath[systemDirLen + fileLen] = L'\0'; + } else { + systemPath[MAX_PATH] = L'\0'; + } + return LoadLibraryW(systemPath); +} + +} + +#endif diff --git a/onlineupdate/source/update/src/mar.h b/onlineupdate/source/update/src/mar.h index 0e9dc1f137bd..31cc3934e395 100644 --- a/onlineupdate/source/update/src/mar.h +++ b/onlineupdate/source/update/src/mar.h @@ -69,7 +69,7 @@ typedef int (* MarItemCallback)(MarFile *mar, const MarItem *item, void *data); */ MarFile *mar_open(const char *path); -#ifdef XP_WIN +#ifdef WNT MarFile *mar_wopen(const wchar_t *path); #endif diff --git a/onlineupdate/source/update/src/mar_create.c b/onlineupdate/source/update/src/mar_create.c index c2ce10126cbd..a87e937fe4a3 100644 --- a/onlineupdate/source/update/src/mar_create.c +++ b/onlineupdate/source/update/src/mar_create.c @@ -13,7 +13,7 @@ #include "mar_cmdline.h" #include "mar.h" -#ifdef XP_WIN +#ifdef WNT #include #else #include diff --git a/onlineupdate/source/update/src/mar_extract.c b/onlineupdate/source/update/src/mar_extract.c index ec1cd6c53446..f3512e99122c 100644 --- a/onlineupdate/source/update/src/mar_extract.c +++ b/onlineupdate/source/update/src/mar_extract.c @@ -12,7 +12,7 @@ #include "mar_private.h" #include "mar.h" -#ifdef XP_WIN +#ifdef WNT #include #include #endif @@ -25,7 +25,7 @@ static int mar_ensure_parent_dir(const char *path) { *slash = '\0'; mar_ensure_parent_dir(path); -#ifdef XP_WIN +#ifdef WNT _mkdir(path); #else mkdir(path, 0755); @@ -43,7 +43,7 @@ static int mar_test_callback(MarFile *mar, const MarItem *item, void *unused) { if (mar_ensure_parent_dir(item->name)) return -1; -#ifdef XP_WIN +#ifdef WNT fd = _open(item->name, _O_BINARY|_O_CREAT|_O_TRUNC|_O_WRONLY, item->flags); #else fd = creat(item->name, item->flags); diff --git a/onlineupdate/source/update/src/mar_private.h b/onlineupdate/source/update/src/mar_private.h index 8a7fb45ccd82..39a77d1ac03e 100644 --- a/onlineupdate/source/update/src/mar_private.h +++ b/onlineupdate/source/update/src/mar_private.h @@ -53,7 +53,7 @@ MOZ_STATIC_ASSERT(sizeof(BLOCKSIZE) < \ /* The mar program is compiled as a host bin so we don't have access to NSPR at runtime. For that reason we use ntohl, htonl, and define HOST_TO_NETWORK64 instead of the NSPR equivalents. */ -#ifdef XP_WIN +#ifdef WNT #include #define ftello _ftelli64 #define fseeko _fseeki64 diff --git a/onlineupdate/source/update/src/mar_read.c b/onlineupdate/source/update/src/mar_read.c index 7be225385403..c7c4bdf19554 100644 --- a/onlineupdate/source/update/src/mar_read.c +++ b/onlineupdate/source/update/src/mar_read.c @@ -11,7 +11,7 @@ #include "mar_private.h" #include "mar.h" -#ifdef XP_WIN +#ifdef WNT #include #else #include @@ -177,7 +177,7 @@ MarFile *mar_open(const char *path) { return mar_fpopen(fp); } -#ifdef XP_WIN +#ifdef WNT MarFile *mar_wopen(const wchar_t *path) { FILE *fp; diff --git a/onlineupdate/source/update/updater/archivereader.cxx b/onlineupdate/source/update/updater/archivereader.cxx index 0bdb99220334..4629d330e5cc 100644 --- a/onlineupdate/source/update/updater/archivereader.cxx +++ b/onlineupdate/source/update/updater/archivereader.cxx @@ -11,7 +11,6 @@ #include "archivereader.h" #include "errors.h" #ifdef WNT -#include "nsAlgorithm.h" // Needed by nsVersionComparator.cpp #include "updatehelper.h" #endif diff --git a/onlineupdate/source/update/updater/loaddlls.cxx b/onlineupdate/source/update/updater/loaddlls.cxx index b910723953f8..541cf4a3a683 100644 --- a/onlineupdate/source/update/updater/loaddlls.cxx +++ b/onlineupdate/source/update/updater/loaddlls.cxx @@ -5,6 +5,9 @@ #ifdef WNT +#ifndef UNICODE +#define UNICODE +#endif #include // Delayed load libraries are loaded when the first symbol is used. diff --git a/onlineupdate/source/update/updater/nsWindowsRestart.cxx b/onlineupdate/source/update/updater/nsWindowsRestart.cxx new file mode 100644 index 000000000000..8623d5117baf --- /dev/null +++ b/onlineupdate/source/update/updater/nsWindowsRestart.cxx @@ -0,0 +1,584 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// This file is not build directly. Instead, it is included in multiple +// shared objects. + +#ifdef nsWindowsRestart_cxx +#error "nsWindowsRestart.cxx is not a header file, and must only be included once." +#else +#define nsWindowsRestart_cxx +#endif + +#ifdef WNT +#include +#endif +#include +#include +#include + +#include + +// Needed for CreateEnvironmentBlock +#include +#pragma comment(lib, "userenv.lib") + +// Adapted from Mozilla's nsCharTraits.h +/* + * Some macros for converting char16_t (UTF-16) to and from Unicode scalar + * values. + * + * Note that UTF-16 represents all Unicode scalar values up to U+10FFFF by + * using "surrogate pairs". These consist of a high surrogate, i.e. a code + * point in the range U+D800 - U+DBFF, and a low surrogate, i.e. a code point + * in the range U+DC00 - U+DFFF, like this: + * + * U+D800 U+DC00 = U+10000 + * U+D800 U+DC01 = U+10001 + * ... + * U+DBFF U+DFFE = U+10FFFE + * U+DBFF U+DFFF = U+10FFFF + * + * These surrogate code points U+D800 - U+DFFF are not themselves valid Unicode + * scalar values and are not well-formed UTF-16 except as high-surrogate / + * low-surrogate pairs. + */ + +#define PLANE1_BASE uint32_t(0x00010000) +// High surrogates are in the range 0xD800 -- OxDBFF +#define NS_IS_HIGH_SURROGATE(u) ((uint32_t(u) & 0xFFFFFC00) == 0xD800) +// Low surrogates are in the range 0xDC00 -- 0xDFFF +#define NS_IS_LOW_SURROGATE(u) ((uint32_t(u) & 0xFFFFFC00) == 0xDC00) +// Faster than testing NS_IS_HIGH_SURROGATE || NS_IS_LOW_SURROGATE +#define IS_SURROGATE(u) ((uint32_t(u) & 0xFFFFF800) == 0xD800) + +// Everything else is not a surrogate: 0x000 -- 0xD7FF, 0xE000 -- 0xFFFF + +// N = (H - 0xD800) * 0x400 + 0x10000 + (L - 0xDC00) +// I wonder whether we could somehow assert that H is a high surrogate +// and L is a low surrogate +#define SURROGATE_TO_UCS4(h, l) (((uint32_t(h) & 0x03FF) << 10) + \ + (uint32_t(l) & 0x03FF) + PLANE1_BASE) + +// Extract surrogates from a UCS4 char +// Reference: the Unicode standard 4.0, section 3.9 +// Since (c - 0x10000) >> 10 == (c >> 10) - 0x0080 and +// 0xD7C0 == 0xD800 - 0x0080, +// ((c - 0x10000) >> 10) + 0xD800 can be simplified to +#define H_SURROGATE(c) char16_t(char16_t(uint32_t(c) >> 10) + \ + char16_t(0xD7C0)) +// where it's to be noted that 0xD7C0 is not bitwise-OR'd +// but added. + +// Since 0x10000 & 0x03FF == 0, +// (c - 0x10000) & 0x03FF == c & 0x03FF so that +// ((c - 0x10000) & 0x03FF) | 0xDC00 is equivalent to +#define L_SURROGATE(c) char16_t(char16_t(uint32_t(c) & uint32_t(0x03FF)) | \ + char16_t(0xDC00)) + +#define IS_IN_BMP(ucs) (uint32_t(ucs) < PLANE1_BASE) +#define UCS2_REPLACEMENT_CHAR char16_t(0xFFFD) + +#define UCS_END uint32_t(0x00110000) +#define IS_VALID_CHAR(c) ((uint32_t(c) < UCS_END) && !IS_SURROGATE(c)) +#define ENSURE_VALID_CHAR(c) (IS_VALID_CHAR(c) ? (c) : UCS2_REPLACEMENT_CHAR) + +// UTF8traits adapted from Mozilla's nsUTF8Utils.h +class UTF8traits +{ +public: + static bool isASCII(char aChar) + { + return (aChar & 0x80) == 0x00; + } + static bool isInSeq(char aChar) + { + return (aChar & 0xC0) == 0x80; + } + static bool is2byte(char aChar) + { + return (aChar & 0xE0) == 0xC0; + } + static bool is3byte(char aChar) + { + return (aChar & 0xF0) == 0xE0; + } + static bool is4byte(char aChar) + { + return (aChar & 0xF8) == 0xF0; + } + static bool is5byte(char aChar) + { + return (aChar & 0xFC) == 0xF8; + } + static bool is6byte(char aChar) + { + return (aChar & 0xFE) == 0xFC; + } +}; + +// UTF8CharEnumerator adapted from Mozilla's nsUTF8Utils.h +/** + * Extract the next UCS-4 character from the buffer and return it. The + * pointer passed in is advanced to the start of the next character in the + * buffer. If non-null, the parameters err and overlong are filled in to + * indicate that the character was represented by an overlong sequence, or + * that an error occurred. + */ + +class UTF8CharEnumerator +{ +public: + static uint32_t NextChar(const char** aBuffer, const char* aEnd, bool* aErr) + { + // If this assert fails check if the buffer is null + assert(aBuffer && *aBuffer); + + const char* p = *aBuffer; + *aErr = false; + + if (p >= aEnd) { + *aErr = true; + + return 0; + } + + char c = *p++; + + if (UTF8traits::isASCII(c)) { + *aBuffer = p; + return c; + } + + uint32_t ucs4; + uint32_t minUcs4; + int32_t state = 0; + + if (!CalcState(c, ucs4, minUcs4, state)) { + std::cerr << "Not a UTF-8 string. This code should only be used for converting from known UTF-8 strings." + << '\n'; + *aErr = true; + + return 0; + } + + while (state--) { + if (p == aEnd) { + *aErr = true; + + return 0; + } + + c = *p++; + + if (!AddByte(c, state, ucs4)) { + *aErr = true; + + return 0; + } + } + + if (ucs4 < minUcs4) { + // Overlong sequence + ucs4 = UCS2_REPLACEMENT_CHAR; + } else if (ucs4 >= 0xD800 && + (ucs4 <= 0xDFFF || ucs4 >= UCS_END)) { + // Surrogates and code points outside the Unicode range. + ucs4 = UCS2_REPLACEMENT_CHAR; + } + + *aBuffer = p; + return ucs4; + } + +private: + static bool CalcState(char aChar, uint32_t& aUcs4, uint32_t& aMinUcs4, + int32_t& aState) + { + if (UTF8traits::is2byte(aChar)) { + aUcs4 = (uint32_t(aChar) << 6) & 0x000007C0L; + aState = 1; + aMinUcs4 = 0x00000080; + } else if (UTF8traits::is3byte(aChar)) { + aUcs4 = (uint32_t(aChar) << 12) & 0x0000F000L; + aState = 2; + aMinUcs4 = 0x00000800; + } else if (UTF8traits::is4byte(aChar)) { + aUcs4 = (uint32_t(aChar) << 18) & 0x001F0000L; + aState = 3; + aMinUcs4 = 0x00010000; + } else if (UTF8traits::is5byte(aChar)) { + aUcs4 = (uint32_t(aChar) << 24) & 0x03000000L; + aState = 4; + aMinUcs4 = 0x00200000; + } else if (UTF8traits::is6byte(aChar)) { + aUcs4 = (uint32_t(aChar) << 30) & 0x40000000L; + aState = 5; + aMinUcs4 = 0x04000000; + } else { + return false; + } + + return true; + } + + static bool AddByte(char aChar, int32_t aState, uint32_t& aUcs4) + { + if (UTF8traits::isInSeq(aChar)) { + int32_t shift = aState * 6; + aUcs4 |= (uint32_t(aChar) & 0x3F) << shift; + return true; + } + + return false; + } +}; + +// ConvertUTF8toUTF16 adapted from Mozilla's nsUTF8Utils.h +/** + * A character sink (see |copy_string| in nsAlgorithm.h) for converting + * UTF-8 to UTF-16 + */ +class ConvertUTF8toUTF16 +{ +public: + typedef char value_type; + typedef char16_t buffer_type; + + explicit ConvertUTF8toUTF16(buffer_type* aBuffer) + : mStart(aBuffer), mBuffer(aBuffer), mErrorEncountered(false) + { + } + + size_t Length() const + { + return mBuffer - mStart; + } + + bool ErrorEncountered() const + { + return mErrorEncountered; + } + + void write(const value_type* aStart, uint32_t aN) + { + if (mErrorEncountered) { + return; + } + + // algorithm assumes utf8 units won't + // be spread across fragments + const value_type* p = aStart; + const value_type* end = aStart + aN; + buffer_type* out = mBuffer; + for (; p != end /* && *p */;) { + bool err; + uint32_t ucs4 = UTF8CharEnumerator::NextChar(&p, end, &err); + + if (err) { + mErrorEncountered = true; + mBuffer = out; + return; + } + + if (ucs4 >= PLANE1_BASE) { + *out++ = (buffer_type)H_SURROGATE(ucs4); + *out++ = (buffer_type)L_SURROGATE(ucs4); + } else { + *out++ = ucs4; + } + } + mBuffer = out; + } + + void write_terminator() + { + *mBuffer = buffer_type(0); + } + +private: + buffer_type* const mStart; + buffer_type* mBuffer; + bool mErrorEncountered; +}; + +/** + * Get the length that the string will take and takes into account the + * additional length if the string needs to be quoted and if characters need to + * be escaped. + */ +static int ArgStrLen(const wchar_t *s) +{ + int backslashes = 0; + int i = wcslen(s); + BOOL hasDoubleQuote = wcschr(s, L'"') != nullptr; + // Only add doublequotes if the string contains a space or a tab + BOOL addDoubleQuotes = wcspbrk(s, L" \t") != nullptr; + + if (addDoubleQuotes) { + i += 2; // initial and final duoblequote + } + + if (hasDoubleQuote) { + while (*s) { + if (*s == '\\') { + ++backslashes; + } else { + if (*s == '"') { + // Escape the doublequote and all backslashes preceding the doublequote + i += backslashes + 1; + } + + backslashes = 0; + } + + ++s; + } + } + + return i; +} + +/** + * Copy string "s" to string "d", quoting the argument as appropriate and + * escaping doublequotes along with any backslashes that immediately precede + * doublequotes. + * The CRT parses this to retrieve the original argc/argv that we meant, + * see STDARGV.C in the MSVC CRT sources. + * + * @return the end of the string + */ +static wchar_t* ArgToString(wchar_t *d, const wchar_t *s) +{ + int backslashes = 0; + BOOL hasDoubleQuote = wcschr(s, L'"') != nullptr; + // Only add doublequotes if the string contains a space or a tab + BOOL addDoubleQuotes = wcspbrk(s, L" \t") != nullptr; + + if (addDoubleQuotes) { + *d = '"'; // initial doublequote + ++d; + } + + if (hasDoubleQuote) { + int i; + while (*s) { + if (*s == '\\') { + ++backslashes; + } else { + if (*s == '"') { + // Escape the doublequote and all backslashes preceding the doublequote + for (i = 0; i <= backslashes; ++i) { + *d = '\\'; + ++d; + } + } + + backslashes = 0; + } + + *d = *s; + ++d; ++s; + } + } else { + wcscpy(d, s); + d += wcslen(s); + } + + if (addDoubleQuotes) { + *d = '"'; // final doublequote + ++d; + } + + return d; +} + +/** + * Creates a command line from a list of arguments. The returned + * string is allocated with "malloc" and should be "free"d. + * + * argv is UTF8 + */ +wchar_t* +MakeCommandLine(int argc, wchar_t **argv) +{ + int i; + int len = 0; + + // The + 1 of the last argument handles the allocation for null termination + for (i = 0; i < argc; ++i) + len += ArgStrLen(argv[i]) + 1; + + // Protect against callers that pass 0 arguments + if (len == 0) + len = 1; + + wchar_t *s = (wchar_t*) malloc(len * sizeof(wchar_t)); + if (!s) + return nullptr; + + wchar_t *c = s; + for (i = 0; i < argc; ++i) { + c = ArgToString(c, argv[i]); + if (i + 1 != argc) { + *c = ' '; + ++c; + } + } + + *c = '\0'; + + return s; +} + +/** + * Convert UTF8 to UTF16 without using the normal XPCOM goop, which we + * can't link to updater.exe. + */ +static char16_t* +AllocConvertUTF8toUTF16(const char *arg) +{ + // UTF16 can't be longer in units than UTF8 + int len = strlen(arg); + char16_t *s = new char16_t[(len + 1) * sizeof(char16_t)]; + if (!s) + return nullptr; + + ConvertUTF8toUTF16 convert(s); + convert.write(arg, len); + convert.write_terminator(); + return s; +} + +static void +FreeAllocStrings(int argc, wchar_t **argv) +{ + while (argc) { + --argc; + delete [] argv[argc]; + } + + delete [] argv; +} + + + +/** + * Launch a child process with the specified arguments. + * @note argv[0] is ignored + * @note The form of this function that takes char **argv expects UTF-8 + */ + +BOOL +WinLaunchChild(const wchar_t *exePath, + int argc, wchar_t **argv, + HANDLE userToken = nullptr, + HANDLE *hProcess = nullptr); + +BOOL +WinLaunchChild(const wchar_t *exePath, + int argc, char **argv, + HANDLE userToken, + HANDLE *hProcess) +{ + wchar_t** argvConverted = new wchar_t*[argc]; + if (!argvConverted) + return FALSE; + + for (int i = 0; i < argc; ++i) { + argvConverted[i] = reinterpret_cast(AllocConvertUTF8toUTF16(argv[i])); + if (!argvConverted[i]) { + FreeAllocStrings(i, argvConverted); + return FALSE; + } + } + + BOOL ok = WinLaunchChild(exePath, argc, argvConverted, userToken, hProcess); + FreeAllocStrings(argc, argvConverted); + return ok; +} + +BOOL +WinLaunchChild(const wchar_t *exePath, + int argc, + wchar_t **argv, + HANDLE userToken, + HANDLE *hProcess) +{ + wchar_t *cl; + BOOL ok; + + cl = MakeCommandLine(argc, argv); + if (!cl) { + return FALSE; + } + + STARTUPINFOW si = {0}; + si.cb = sizeof(STARTUPINFOW); + si.lpDesktop = L"winsta0\\Default"; + PROCESS_INFORMATION pi = {0}; + + if (userToken == nullptr) { + ok = CreateProcessW(exePath, + cl, + nullptr, // no special security attributes + nullptr, // no special thread attributes + FALSE, // don't inherit filehandles + 0, // creation flags + nullptr, // inherit my environment + nullptr, // use my current directory + &si, + &pi); + } else { + // Create an environment block for the process we're about to start using + // the user's token. + LPVOID environmentBlock = nullptr; + if (!CreateEnvironmentBlock(&environmentBlock, userToken, TRUE)) { + environmentBlock = nullptr; + } + + ok = CreateProcessAsUserW(userToken, + exePath, + cl, + nullptr, // no special security attributes + nullptr, // no special thread attributes + FALSE, // don't inherit filehandles + 0, // creation flags + environmentBlock, + nullptr, // use my current directory + &si, + &pi); + + if (environmentBlock) { + DestroyEnvironmentBlock(environmentBlock); + } + } + + if (ok) { + if (hProcess) { + *hProcess = pi.hProcess; // the caller now owns the HANDLE + } else { + CloseHandle(pi.hProcess); + } + CloseHandle(pi.hThread); + } else { + LPVOID lpMsgBuf = nullptr; + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf, + 0, + nullptr); + wprintf(L"Error restarting: %s\n", lpMsgBuf ? lpMsgBuf : L"(null)"); + if (lpMsgBuf) + LocalFree(lpMsgBuf); + } + + free(cl); + + return ok; +} diff --git a/onlineupdate/source/update/updater/progressui_win.cxx b/onlineupdate/source/update/updater/progressui_win.cxx index d0b268edaa26..3cbbc6b9891d 100644 --- a/onlineupdate/source/update/updater/progressui_win.cxx +++ b/onlineupdate/source/update/updater/progressui_win.cxx @@ -6,6 +6,9 @@ #ifdef WNT #include +#ifndef UNICODE +#define UNICODE +#endif #include #include #include diff --git a/onlineupdate/source/update/updater/updater.cxx b/onlineupdate/source/update/updater/updater.cxx index 998a3109bf3f..1685995c6fdf 100644 --- a/onlineupdate/source/update/updater/updater.cxx +++ b/onlineupdate/source/update/updater/updater.cxx @@ -1802,7 +1802,7 @@ PatchIfFile::Finish(int status) //----------------------------------------------------------------------------- #ifdef WNT -#include "nsWindowsRestart.cpp" +#include "nsWindowsRestart.cxx" #include "nsWindowsHelpers.h" #include "uachelper.h" #include "pathhash.h" diff --git a/onlineupdate/source/update/updater/xpcom/glue/nsVersionComparator.cxx b/onlineupdate/source/update/updater/xpcom/glue/nsVersionComparator.cxx index 1193f867efa7..3f859db06aae 100644 --- a/onlineupdate/source/update/updater/xpcom/glue/nsVersionComparator.cxx +++ b/onlineupdate/source/update/updater/xpcom/glue/nsVersionComparator.cxx @@ -11,7 +11,18 @@ #include #if defined(WNT) && !defined(UPDATER_NO_STRING_GLUE_STL) #include -#include "nsStringGlue.h" +#include +#include "mozilla/Char16.h" +#endif + +#ifdef WNT +// from Mozilla's nsAlgorithm.h +template +inline const T& +XPCOM_MIN(const T& aA, const T& aB) +{ + return aB < aA ? aB : aA; +} #endif struct VersionPart @@ -301,14 +312,14 @@ namespace mozilla { #ifdef WNT int32_t -CompareVersions(const char16_t* aStrA, const char16_t* aStrB) +CompareVersions(const wchar_t* aStrA, const wchar_t* aStrB) { - wchar_t* A2 = wcsdup(char16ptr_t(aStrA)); + wchar_t* A2 = wcsdup(aStrA); if (!A2) { return 1; } - wchar_t* B2 = wcsdup(char16ptr_t(aStrB)); + wchar_t* B2 = wcsdup(aStrB); if (!B2) { free(A2); return 1; diff --git a/onlineupdate/source/update/updater/xpcom/glue/nsVersionComparator.h b/onlineupdate/source/update/updater/xpcom/glue/nsVersionComparator.h index 431d181ef722..a54c7fdd10e2 100644 --- a/onlineupdate/source/update/updater/xpcom/glue/nsVersionComparator.h +++ b/onlineupdate/source/update/updater/xpcom/glue/nsVersionComparator.h @@ -12,7 +12,9 @@ #include #if defined(WNT) && !defined(UPDATER_NO_STRING_GLUE_STL) #include -#include "nsStringGlue.h" +#include +#include "mozilla/Char16.h" + #endif /** @@ -45,7 +47,7 @@ namespace mozilla { int32_t CompareVersions(const char* aStrA, const char* aStrB); #ifdef WNT -int32_t CompareVersions(const char16_t* aStrA, const char16_t* aStrB); +int32_t CompareVersions(const wchar_t* aStrA, const wchar_t* aStrB); #endif struct Version @@ -121,13 +123,13 @@ private: #ifdef WNT struct VersionW { - VersionW(const char16_t* aVersionStringW) + VersionW(const wchar_t* aVersionStringW) { versionContentW = - reinterpret_cast(wcsdup(char16ptr_t(aVersionStringW))); + reinterpret_cast(wcsdup(aVersionStringW)); } - const char16_t* ReadContentW() const + const wchar_t* ReadContentW() const { return versionContentW; } @@ -163,7 +165,7 @@ struct VersionW } private: - char16_t* versionContentW; + wchar_t* versionContentW; }; #endif -- cgit