Merge viewer-bugsplat

master
Ansariel 2018-12-16 13:04:08 +01:00
commit 8b6392c0aa
38 changed files with 656 additions and 239 deletions

View File

@ -3444,9 +3444,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>c543e73c35c605eaf509bc7651c11227</string>
<string>e2bef561238448fe512146baa6dacabc</string>
<key>url</key>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/27348/219718/viewer_manager-2.0.521526-darwin64-521526.tar.bz2</string>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/28859/240421/viewer_manager-2.0.522507-darwin64-522507.tar.bz2</string>
</map>
<key>name</key>
<string>darwin64</string>
@ -3480,9 +3480,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>fec612973e0d70f82da8c8f22a10c6f3</string>
<string>75cdf1afc293423553b6d190ce422412</string>
<key>url</key>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/27349/219725/viewer_manager-2.0.521526-windows-521526.tar.bz2</string>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/28858/240427/viewer_manager-2.0.522507-windows-522507.tar.bz2</string>
</map>
<key>name</key>
<string>windows</string>
@ -3493,7 +3493,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>source_type</key>
<string>hg</string>
<key>version</key>
<string>2.0.521526</string>
<string>2.0.522507</string>
</map>
<key>vlc-bin</key>
<map>

View File

@ -77,6 +77,7 @@ if (WINDOWS)
wldap32
gdi32
user32
ole32
dbghelp
)
else (WINDOWS)

View File

@ -30,6 +30,7 @@
#if LL_WINDOWS
#include "llwin32headerslean.h"
#include <stdlib.h> // Windows errno
#include <vector>
#else
#include <errno.h>
#endif
@ -134,8 +135,10 @@ int warnif(const std::string& desc, const std::string& filename, int rc, int acc
{
// Only do any of this stuff (before LL_ENDL) if it will be logged.
LL_DEBUGS("LLFile") << empty;
const char* TEMP = getenv("TEMP");
if (! TEMP)
// would be nice to use LLDir for this, but dependency goes the
// wrong way
const char* TEMP = LLFile::tmpdir();
if (! (TEMP && *TEMP))
{
LL_CONT << "No $TEMP, not running 'handle'";
}
@ -385,17 +388,13 @@ const char *LLFile::tmpdir()
#if LL_WINDOWS
sep = '\\';
DWORD len = GetTempPathW(0, L"");
llutf16string utf16path;
utf16path.resize(len + 1);
len = GetTempPathW(static_cast<DWORD>(utf16path.size()), &utf16path[0]);
utf8path = utf16str_to_utf8str(utf16path);
std::vector<wchar_t> utf16path(MAX_PATH + 1);
GetTempPathW(utf16path.size(), &utf16path[0]);
utf8path = ll_convert_wide_to_string(&utf16path[0]);
#else
sep = '/';
char *env = getenv("TMPDIR");
utf8path = env ? env : "/tmp/";
utf8path = LLStringUtil::getenv("TMPDIR", "/tmp/");
#endif
if (utf8path[utf8path.size() - 1] != sep)
{

View File

@ -111,6 +111,9 @@
#endif
// Although thread_local is now a standard storage class, we can't just
// #define LL_THREAD_LOCAL as thread_local because the *usage* is different.
// We'll have to take the time to change LL_THREAD_LOCAL declarations by hand.
#if LL_WINDOWS
# define LL_THREAD_LOCAL __declspec(thread)
#else
@ -187,6 +190,24 @@
#define LL_DLLIMPORT
#endif // LL_WINDOWS
#if ! defined(LL_WINDOWS)
#define LL_WCHAR_T_NATIVE 1
#else // LL_WINDOWS
// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
// _WCHAR_T_DEFINED is defined if wchar_t is provided at all.
// Specifically, it has value 1 if wchar_t is an intrinsic type, else empty.
// _NATIVE_WCHAR_T_DEFINED has value 1 if wchar_t is intrinsic, else undefined.
// For years we have compiled with /Zc:wchar_t-, meaning that wchar_t is a
// typedef for unsigned short (in stddef.h). Lore has it that one of our
// proprietary binary-only libraries has traditionally been built that way and
// therefore EVERYTHING ELSE requires it. Therefore, in a typical Linden
// Windows build, _WCHAR_T_DEFINED is defined but empty, while
// _NATIVE_WCHAR_T_DEFINED is undefined.
# if defined(_NATIVE_WCHAR_T_DEFINED)
# define LL_WCHAR_T_NATIVE 1
# endif // _NATIVE_WCHAR_T_DEFINED
#endif // LL_WINDOWS
#if LL_COMMON_LINK_SHARED
// CMake automagically defines llcommon_EXPORTS only when building llcommon
// sources, and only when llcommon is a shared library (i.e. when

View File

@ -1205,30 +1205,9 @@ static LLProcess::Status interpret_status(int status)
/// GetLastError()/FormatMessage() boilerplate
static std::string WindowsErrorString(const std::string& operation)
{
int result = GetLastError();
LPTSTR error_str = 0;
if (FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
result,
0,
(LPTSTR)&error_str,
0,
NULL)
!= 0)
{
// convert from wide-char string to multi-byte string
char message[256];
wcstombs(message, error_str, sizeof(message));
message[sizeof(message)-1] = 0;
LocalFree(error_str);
// convert to std::string to trim trailing whitespace
std::string mbsstr(message);
mbsstr.erase(mbsstr.find_last_not_of(" \t\r\n"));
return STRINGIZE(operation << " failed (" << result << "): " << mbsstr);
}
return STRINGIZE(operation << " failed (" << result
<< "), but FormatMessage() did not explain");
auto result = GetLastError();
return STRINGIZE(operation << " failed (" << result << "): "
<< windows_message<std::string>(result));
}
/*****************************************************************************

View File

@ -30,6 +30,7 @@
#include "llerror.h"
#include "llfasttimer.h"
#include "llsd.h"
#include <vector>
#if LL_WINDOWS
#include "llwin32headerslean.h"
@ -744,6 +745,11 @@ namespace snprintf_hack
}
}
std::string ll_convert_wide_to_string(const wchar_t* in)
{
return ll_convert_wide_to_string(in, CP_UTF8);
}
std::string ll_convert_wide_to_string(const wchar_t* in, unsigned int code_page)
{
std::string out;
@ -781,7 +787,12 @@ std::string ll_convert_wide_to_string(const wchar_t* in, unsigned int code_page)
return out;
}
wchar_t* ll_convert_string_to_wide(const std::string& in, unsigned int code_page)
std::wstring ll_convert_string_to_wide(const std::string& in)
{
return ll_convert_string_to_wide(in, CP_UTF8);
}
std::wstring ll_convert_string_to_wide(const std::string& in, unsigned int code_page)
{
// From review:
// We can preallocate a wide char buffer that is the same length (in wchar_t elements) as the utf8 input,
@ -791,28 +802,148 @@ wchar_t* ll_convert_string_to_wide(const std::string& in, unsigned int code_page
// but we *are* seeing string operations taking a bunch of time, especially when constructing widgets.
// int output_str_len = MultiByteToWideChar(code_page, 0, in.c_str(), in.length(), NULL, 0);
// reserve place to NULL terminator
int output_str_len = in.length();
wchar_t* w_out = new wchar_t[output_str_len + 1];
// reserve an output buffer that will be destroyed on exit, with a place
// to put NULL terminator
std::vector<wchar_t> w_out(in.length() + 1);
memset(w_out, 0, output_str_len + 1);
int real_output_str_len = MultiByteToWideChar (code_page, 0, in.c_str(), in.length(), w_out, output_str_len);
memset(&w_out[0], 0, w_out.size());
int real_output_str_len = MultiByteToWideChar(code_page, 0, in.c_str(), in.length(),
&w_out[0], w_out.size() - 1);
//looks like MultiByteToWideChar didn't add null terminator to converted string, see EXT-4858.
w_out[real_output_str_len] = 0;
return w_out;
// construct string<wchar_t> from our temporary output buffer
return {&w_out[0]};
}
LLWString ll_convert_wide_to_wstring(const std::wstring& in)
{
// This function, like its converse, is a placeholder, encapsulating a
// guilty little hack: the only "official" way nat has found to convert
// between std::wstring (16 bits on Windows) and LLWString (UTF-32) is
// by using iconv, which we've avoided so far. It kinda sorta works to
// just copy individual characters...
// The point is that if/when we DO introduce some more official way to
// perform such conversions, we should only have to call it here.
return { in.begin(), in.end() };
}
std::wstring ll_convert_wstring_to_wide(const LLWString& in)
{
// See comments in ll_convert_wide_to_wstring()
return { in.begin(), in.end() };
}
std::string ll_convert_string_to_utf8_string(const std::string& in)
{
wchar_t* w_mesg = ll_convert_string_to_wide(in, CP_ACP);
std::string out_utf8(ll_convert_wide_to_string(w_mesg, CP_UTF8));
delete[] w_mesg;
auto w_mesg = ll_convert_string_to_wide(in, CP_ACP);
std::string out_utf8(ll_convert_wide_to_string(w_mesg.c_str(), CP_UTF8));
return out_utf8;
}
#endif // LL_WINDOWS
namespace
{
void HeapFree_deleter(void* ptr)
{
// instead of LocalFree(), per https://stackoverflow.com/a/31541205
HeapFree(GetProcessHeap(), NULL, ptr);
}
} // anonymous namespace
template<>
std::wstring windows_message<std::wstring>(DWORD error)
{
// derived from https://stackoverflow.com/a/455533
wchar_t* rawptr = nullptr;
auto okay = FormatMessageW(
// use system message tables for GetLastError() codes
FORMAT_MESSAGE_FROM_SYSTEM |
// internally allocate buffer and return its pointer
FORMAT_MESSAGE_ALLOCATE_BUFFER |
// you cannot pass insertion parameters (thanks Gandalf)
FORMAT_MESSAGE_IGNORE_INSERTS |
// ignore line breaks in message definition text
FORMAT_MESSAGE_MAX_WIDTH_MASK,
NULL, // lpSource, unused with FORMAT_MESSAGE_FROM_SYSTEM
error, // dwMessageId
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // dwLanguageId
(LPWSTR)&rawptr, // lpBuffer: force-cast wchar_t** to wchar_t*
0, // nSize, unused with FORMAT_MESSAGE_ALLOCATE_BUFFER
NULL); // Arguments, unused
// make a unique_ptr from rawptr so it gets cleaned up properly
std::unique_ptr<wchar_t, void(*)(void*)> bufferptr(rawptr, HeapFree_deleter);
if (okay && bufferptr)
{
// got the message, return it ('okay' is length in characters)
return { bufferptr.get(), okay };
}
// did not get the message, synthesize one
auto format_message_error = GetLastError();
std::wostringstream out;
out << L"GetLastError() " << error << L" (FormatMessageW() failed with "
<< format_message_error << L")";
return out.str();
}
boost::optional<std::wstring> llstring_getoptenv(const std::string& key)
{
auto wkey = ll_convert_string_to_wide(key);
// Take a wild guess as to how big the buffer should be.
std::vector<wchar_t> buffer(1024);
auto n = GetEnvironmentVariableW(wkey.c_str(), &buffer[0], buffer.size());
// If our initial guess was too short, n will indicate the size (in
// wchar_t's) that buffer should have been, including the terminating nul.
if (n > (buffer.size() - 1))
{
// make it big enough
buffer.resize(n);
// and try again
n = GetEnvironmentVariableW(wkey.c_str(), &buffer[0], buffer.size());
}
// did that (ultimately) succeed?
if (n)
{
// great, return populated boost::optional
return boost::optional<std::wstring>(&buffer[0]);
}
// not successful
auto last_error = GetLastError();
// Don't bother warning for NOT_FOUND; that's an expected case
if (last_error != ERROR_ENVVAR_NOT_FOUND)
{
LL_WARNS() << "GetEnvironmentVariableW('" << key << "') failed: "
<< windows_message<std::string>(last_error) << LL_ENDL;
}
// return empty boost::optional
return {};
}
#else // ! LL_WINDOWS
boost::optional<std::string> llstring_getoptenv(const std::string& key)
{
auto found = getenv(key.c_str());
if (found)
{
// return populated boost::optional
return boost::optional<std::string>(found);
}
else
{
// return empty boost::optional
return {};
}
}
#endif // ! LL_WINDOWS
long LLStringOps::sPacificTimeOffset = 0;
long LLStringOps::sLocalTimeOffset = 0;

View File

@ -27,6 +27,7 @@
#ifndef LL_LLSTRING_H
#define LL_LLSTRING_H
#include <boost/optional/optional.hpp>
#include <string>
#include <cstdio>
//#include <locale>
@ -341,6 +342,19 @@ public:
const string_type& string,
const string_type& substr);
/**
* get environment string value with proper Unicode handling
* (key is always UTF-8)
* detect absence by return value == dflt
*/
static string_type getenv(const std::string& key, const string_type& dflt="");
/**
* get optional environment string value with proper Unicode handling
* (key is always UTF-8)
* detect absence by (! return value)
*/
static boost::optional<string_type> getoptenv(const std::string& key);
static void addCRLF(string_type& string);
static void removeCRLF(string_type& string);
static void removeWindowsCR(string_type& string);
@ -500,6 +514,37 @@ LL_COMMON_API bool iswindividual(llwchar elem);
* Unicode support
*/
/// generic conversion aliases
template<typename TO, typename FROM, typename Enable=void>
struct ll_convert_impl
{
// Don't even provide a generic implementation. We specialize for every
// combination we do support.
TO operator()(const FROM& in) const;
};
// Use a function template to get the nice ll_convert<TO>(from_value) API.
template<typename TO, typename FROM>
TO ll_convert(const FROM& in)
{
return ll_convert_impl<TO, FROM>()(in);
}
// degenerate case
template<typename T>
struct ll_convert_impl<T, T>
{
T operator()(const T& in) const { return in; }
};
// specialize ll_convert_impl<TO, FROM> to return EXPR
#define ll_convert_alias(TO, FROM, EXPR) \
template<> \
struct ll_convert_impl<TO, FROM> \
{ \
TO operator()(const FROM& in) const { return EXPR; } \
}
// Make the incoming string a utf8 string. Replaces any unknown glyph
// with the UNKNOWN_CHARACTER. Once any unknown glyph is found, the rest
// of the data may not be recovered.
@ -507,30 +552,88 @@ LL_COMMON_API std::string rawstr_to_utf8(const std::string& raw);
//
// We should never use UTF16 except when communicating with Win32!
// https://docs.microsoft.com/en-us/cpp/cpp/char-wchar-t-char16-t-char32-t
// nat 2018-12-14: I consider the whole llutf16string thing a mistake, because
// the Windows APIs we want to call are all defined in terms of wchar_t*
// (or worse, LPCTSTR).
// https://docs.microsoft.com/en-us/windows/desktop/winprog/windows-data-types
// While there is no point coding for an ASCII-only world (! defined(UNICODE)),
// use of U16 and llutf16string for Windows APIs locks in /Zc:wchar_t-. Going
// forward, we should code in terms of wchar_t and std::wstring so as to
// support either setting of /Zc:wchar_t.
// The first link above states that char can be used to hold ASCII or any
// multi-byte character set, and distinguishes wchar_t (UTF-16LE), char16_t
// (UTF-16) and char32_t (UTF-32). Nonetheless, within this code base:
// * char and std::string always hold UTF-8 (of which ASCII is a subset). It
// is a BUG if they are used to pass strings in any other multi-byte
// encoding.
// * wchar_t and std::wstring should be our interface to Windows wide-string
// APIs, and therefore hold UTF-16LE.
// * U16 and llutf16string are the previous but DEPRECATED UTF-16LE type. Do
// not introduce new uses of U16 or llutf16string for string data.
// * llwchar and LLWString hold UTF-32 strings.
// * Do not introduce char16_t or std::u16string.
// * Do not introduce char32_t or std::u32string.
//
// This typedef may or may not be identical to std::wstring, depending on
// LL_WCHAR_T_NATIVE.
typedef std::basic_string<U16> llutf16string;
#if ! defined(LL_WCHAR_T_NATIVE)
// wchar_t is identical to U16, and std::wstring is identical to llutf16string.
// Defining an ll_convert alias involving llutf16string would collide with the
// comparable preferred alias involving std::wstring. (In this scenario, if
// you pass llutf16string, it will engage the std::wstring specialization.)
#define ll_convert_u16_alias(TO, FROM, EXPR) // nothing
#else // defined(LL_WCHAR_T_NATIVE)
// wchar_t is a distinct native type, so llutf16string is also a distinct
// type, and there IS a point to converting separately to/from llutf16string.
// (But why? Windows APIs are still defined in terms of wchar_t, and
// in this scenario llutf16string won't work for them!)
#define ll_convert_u16_alias(TO, FROM, EXPR) ll_convert_alias(TO, FROM, EXPR)
#if LL_WINDOWS
// LL_WCHAR_T_NATIVE is defined on non-Windows systems because, in fact,
// wchar_t is native. Everywhere but Windows, we use it for llwchar (see
// stdtypes.h). That makes LLWString identical to std::wstring, so these
// aliases for std::wstring would collide with those for LLWString. Only
// define on Windows, where converting between std::wstring and llutf16string
// means copying chars.
ll_convert_alias(llutf16string, std::wstring, llutf16string(in.begin(), in.end()));
ll_convert_alias(std::wstring, llutf16string, std::wstring(in.begin(), in.end()));
#endif // LL_WINDOWS
#endif // defined(LL_WCHAR_T_NATIVE)
LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len);
LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str);
ll_convert_u16_alias(LLWString, llutf16string, utf16str_to_wstring(in));
LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len);
LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str);
ll_convert_u16_alias(llutf16string, LLWString, wstring_to_utf16str(in));
LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str, S32 len);
LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str );
ll_convert_u16_alias(llutf16string, std::string, utf8str_to_utf16str(in));
LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str, S32 len);
LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str);
// Same function, better name. JC
inline LLWString utf8string_to_wstring(const std::string& utf8_string) { return utf8str_to_wstring(utf8_string); }
// best name of all
ll_convert_alias(LLWString, std::string, utf8string_to_wstring(in));
//
LL_COMMON_API S32 wchar_to_utf8chars(llwchar inchar, char* outchars);
LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str, S32 len);
LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str);
ll_convert_alias(std::string, LLWString, wstring_to_utf8str(in));
LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str, S32 len);
LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str);
ll_convert_u16_alias(std::string, llutf16string, utf16str_to_utf8str(in));
#if LL_WINDOWS
inline std::string wstring_to_utf8str(const llutf16string &utf16str) { return utf16str_to_utf8str(utf16str);}
@ -644,22 +747,77 @@ using snprintf_hack::snprintf;
* This replaces the unsafe W2A macro from ATL.
*/
LL_COMMON_API std::string ll_convert_wide_to_string(const wchar_t* in, unsigned int code_page);
LL_COMMON_API std::string ll_convert_wide_to_string(const wchar_t* in); // default CP_UTF8
inline std::string ll_convert_wide_to_string(const std::wstring& in, unsigned int code_page)
{
return ll_convert_wide_to_string(in.c_str(), code_page);
}
inline std::string ll_convert_wide_to_string(const std::wstring& in)
{
return ll_convert_wide_to_string(in.c_str());
}
ll_convert_alias(std::string, std::wstring, ll_convert_wide_to_string(in));
/**
* Converts a string to wide string.
*
* It will allocate memory for result string with "new []". Don't forget to release it with "delete []".
*/
LL_COMMON_API wchar_t* ll_convert_string_to_wide(const std::string& in, unsigned int code_page);
LL_COMMON_API std::wstring ll_convert_string_to_wide(const std::string& in,
unsigned int code_page);
LL_COMMON_API std::wstring ll_convert_string_to_wide(const std::string& in);
// default CP_UTF8
ll_convert_alias(std::wstring, std::string, ll_convert_string_to_wide(in));
/**
* Converts incoming string into urf8 string
* Convert a Windows wide string to our LLWString
*/
LL_COMMON_API LLWString ll_convert_wide_to_wstring(const std::wstring& in);
ll_convert_alias(LLWString, std::wstring, ll_convert_wide_to_wstring(in));
/**
* Convert LLWString to Windows wide string
*/
LL_COMMON_API std::wstring ll_convert_wstring_to_wide(const LLWString& in);
ll_convert_alias(std::wstring, LLWString, ll_convert_wstring_to_wide(in));
/**
* Converts incoming string into utf8 string
*
*/
LL_COMMON_API std::string ll_convert_string_to_utf8_string(const std::string& in);
/// Get Windows message string for passed GetLastError() code
// VS 2013 doesn't let us forward-declare this template, which is what we
// started with, so the implementation could reference the specialization we
// haven't yet declared. Somewhat weirdly, just stating the generic
// implementation in terms of the specialization works, even in this order...
// the general case is just a conversion from the sole implementation
// Microsoft says DWORD is a typedef for unsigned long
// https://docs.microsoft.com/en-us/windows/desktop/winprog/windows-data-types
// so rather than drag windows.h into everybody's include space...
template<typename STRING>
STRING windows_message(unsigned long error)
{
return ll_convert<STRING>(windows_message<std::wstring>(error));
}
/// There's only one real implementation
template<>
LL_COMMON_API std::wstring windows_message<std::wstring>(unsigned long error);
/// Get Windows message string, implicitly calling GetLastError()
template<typename STRING>
STRING windows_message() { return windows_message<STRING>(GetLastError()); }
//@}
#endif // LL_WINDOWS
LL_COMMON_API boost::optional<std::wstring> llstring_getoptenv(const std::string& key);
#else // ! LL_WINDOWS
LL_COMMON_API boost::optional<std::string> llstring_getoptenv(const std::string& key);
#endif // ! LL_WINDOWS
/**
* Many of the 'strip' and 'replace' methods of LLStringUtilBase need
@ -1602,6 +1760,37 @@ bool LLStringUtilBase<T>::endsWith(
return (idx == (string.size() - substr.size()));
}
// static
template<class T>
auto LLStringUtilBase<T>::getoptenv(const std::string& key) -> boost::optional<string_type>
{
auto found(llstring_getoptenv(key));
if (found)
{
// return populated boost::optional
return { ll_convert<string_type>(*found) };
}
else
{
// empty boost::optional
return {};
}
}
// static
template<class T>
auto LLStringUtilBase<T>::getenv(const std::string& key, const string_type& dflt) -> string_type
{
auto found(getoptenv(key));
if (found)
{
return *found;
}
else
{
return dflt;
}
}
template<class T>
BOOL LLStringUtilBase<T>::convertToBOOL(const string_type& string, BOOL& value)

View File

@ -37,7 +37,12 @@ typedef signed int S32;
typedef unsigned int U32;
#if LL_WINDOWS
// Windows wchar_t is 16-bit
// https://docs.microsoft.com/en-us/cpp/build/reference/zc-wchar-t-wchar-t-is-native-type
// https://docs.microsoft.com/en-us/cpp/cpp/fundamental-types-cpp
// Windows wchar_t is 16-bit, whichever way /Zc:wchar_t is set. In effect,
// Windows wchar_t is always a typedef, either for unsigned short or __wchar_t.
// (__wchar_t, available either way, is Microsoft's native 2-byte wchar_t type.)
// In any case, llwchar should be a UTF-32 type.
typedef U32 llwchar;
#else
typedef wchar_t llwchar;

View File

@ -26,6 +26,7 @@
#include "wrapllerrs.h"
#include "llevents.h"
#include "llprocess.h"
#include "llstring.h"
#include "stringize.h"
#include "StringVec.h"
#include <functional>
@ -198,14 +199,12 @@ namespace tut
// basename.
reader_module(LLProcess::basename(
reader.getName().substr(0, reader.getName().length()-3))),
pPYTHON(getenv("PYTHON")),
PYTHON(pPYTHON? pPYTHON : "")
PYTHON(LLStringUtil::getenv("PYTHON"))
{
ensure("Set PYTHON to interpreter pathname", pPYTHON);
ensure("Set PYTHON to interpreter pathname", !PYTHON.empty());
}
NamedExtTempFile reader;
const std::string reader_module;
const char* pPYTHON;
const std::string PYTHON;
};
typedef test_group<llleap_data> llleap_group;

View File

@ -34,6 +34,7 @@
#include "stringize.h"
#include "llsdutil.h"
#include "llevents.h"
#include "llstring.h"
#include "wrapllerrs.h"
#if defined(LL_WINDOWS)
@ -142,8 +143,8 @@ struct PythonProcessLauncher
mDesc(desc),
mScript("py", script)
{
const char* PYTHON(getenv("PYTHON"));
tut::ensure("Set $PYTHON to the Python interpreter", PYTHON);
auto PYTHON(LLStringUtil::getenv("PYTHON"));
tut::ensure("Set $PYTHON to the Python interpreter", !PYTHON.empty());
mParams.desc = desc + " script";
mParams.executable = PYTHON;

View File

@ -41,6 +41,7 @@ typedef U32 uint32_t;
#include <sys/stat.h>
#include <sys/wait.h>
#include "llprocess.h"
#include "llstring.h"
#endif
#include "boost/range.hpp"
@ -1705,8 +1706,8 @@ namespace tut
template <typename CONTENT>
void python(const std::string& desc, const CONTENT& script, int expect=0)
{
const char* PYTHON(getenv("PYTHON"));
ensure("Set $PYTHON to the Python interpreter", PYTHON);
auto PYTHON(LLStringUtil::getenv("PYTHON"));
ensure("Set $PYTHON to the Python interpreter", !PYTHON.empty());
NamedTempFile scriptfile("py", script);
@ -1714,7 +1715,7 @@ namespace tut
std::string q("\"");
std::string qPYTHON(q + PYTHON + q);
std::string qscript(q + scriptfile.getName() + q);
int rc = _spawnl(_P_WAIT, PYTHON, qPYTHON.c_str(), qscript.c_str(), NULL);
int rc = _spawnl(_P_WAIT, PYTHON.c_str(), qPYTHON.c_str(), qscript.c_str(), NULL);
if (rc == -1)
{
char buffer[256];

View File

@ -34,6 +34,7 @@
#include "llsd.h"
#include "llhost.h"
#include "llexception.h"
#include "llstring.h"
#include "stringize.h"
#include <map>
#include <string>
@ -46,12 +47,7 @@ struct CommtestError: public LLException
static bool query_verbose()
{
const char* cbose = getenv("INTEGRATION_TEST_VERBOSE");
if (! cbose)
{
cbose = "1";
}
std::string strbose(cbose);
std::string strbose(LLStringUtil::getenv("INTEGRATION_TEST_VERBOSE", "1"));
return (! (strbose == "0" || strbose == "off" ||
strbose == "false" || strbose == "quiet"));
}

View File

@ -41,6 +41,7 @@
#include "llpumpio.h"
#include "lliosocket.h"
#include "llstring.h"
#include "stringize.h"
#include "llcleanup.h"
@ -50,13 +51,13 @@ namespace tut
{
public:
HTTPClientTestData():
PORT(getenv("PORT")),
PORT(LLStringUtil::getenv("PORT")),
// Turning NULL PORT into empty string doesn't make things work;
// that's just to keep this initializer from blowing up. We test
// PORT separately in the constructor body.
local_server(STRINGIZE("http://127.0.0.1:" << (PORT? PORT : "") << "/"))
local_server(STRINGIZE("http://127.0.0.1:" << PORT << "/"))
{
ensure("Set environment variable PORT to local test server port", PORT);
ensure("Set environment variable PORT to local test server port", !PORT.empty());
apr_pool_create(&mPool, NULL);
LLCurl::initClass(false);
mClientPump = new LLPumpIO(mPool);
@ -87,7 +88,7 @@ namespace tut
}
}
const char* const PORT;
const std::string PORT;
const std::string local_server;
private:

View File

@ -44,6 +44,12 @@
// Third party library includes
#include <boost/tokenizer.hpp>
#if LL_WINDOWS
#include <Shlobj.h>
#include <Knownfolders.h>
#include <Objbase.h>
#endif // LL_WINDOWS
const S32 BOLD_OFFSET = 1;
// static class members
@ -1156,33 +1162,24 @@ LLFontGL* LLFontGL::getFontDefault()
// static
std::string LLFontGL::getFontPathSystem()
{
std::string system_path;
#if LL_DARWIN
// HACK for Mac OS X
return "/System/Library/Fonts/";
// Try to figure out where the system's font files are stored.
char *system_root = NULL;
#if LL_WINDOWS
system_root = getenv("SystemRoot"); /* Flawfinder: ignore */
if (!system_root)
{
LL_WARNS() << "SystemRoot not found, attempting to load fonts from default path." << LL_ENDL;
}
#elif LL_WINDOWS
wchar_t *pwstr = NULL;
HRESULT okay = SHGetKnownFolderPath(FOLDERID_Fonts, 0, NULL, &pwstr);
if (SUCCEEDED(okay) && pwstr)
{
std::string fontpath(ll_convert_wide_to_string(pwstr));
// SHGetKnownFolderPath() contract requires us to free pwstr
CoTaskMemFree(pwstr);
return fontpath;
}
#endif
if (system_root)
{
system_path = llformat("%s/fonts/", system_root);
}
else
{
#if LL_WINDOWS
// HACK for windows 98/Me
system_path = "/WINDOWS/FONTS/";
#elif LL_DARWIN
// HACK for Mac OS X
system_path = "/System/Library/Fonts/";
#endif
}
return system_path;
LL_WARNS() << "Could not determine system fonts path" << LL_ENDL;
return {};
}

View File

@ -29,6 +29,7 @@
#include "lldir_linux.h"
#include "llerror.h"
#include "llrand.h"
#include "llstring.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
@ -40,28 +41,24 @@ static std::string getCurrentUserHome(char* fallback)
{
const uid_t uid = getuid();
struct passwd *pw;
char *result_cstr = fallback;
pw = getpwuid(uid);
if ((pw != NULL) && (pw->pw_dir != NULL))
{
result_cstr = (char*) pw->pw_dir;
return pw->pw_dir;
}
LL_INFOS() << "Couldn't detect home directory from passwd - trying $HOME" << LL_ENDL;
auto home_env = LLStringUtil::getoptenv("HOME");
if (home_env)
{
return *home_env;
}
else
{
LL_INFOS() << "Couldn't detect home directory from passwd - trying $HOME" << LL_ENDL;
const char *const home_env = getenv("HOME"); /* Flawfinder: ignore */
if (home_env)
{
result_cstr = (char*) home_env;
}
else
{
LL_WARNS() << "Couldn't detect home directory! Falling back to " << fallback << LL_ENDL;
}
LL_WARNS() << "Couldn't detect home directory! Falling back to " << fallback << LL_ENDL;
return fallback;
}
return std::string(result_cstr);
}
@ -156,18 +153,18 @@ void LLDir_Linux::initAppDirs(const std::string &app_name,
if (!app_read_only_data_dir.empty())
{
mAppRODataDir = app_read_only_data_dir;
mSkinBaseDir = mAppRODataDir + mDirDelimiter + "skins";
mSkinBaseDir = add(mAppRODataDir, "skins");
}
mAppName = app_name;
std::string upper_app_name(app_name);
LLStringUtil::toUpper(upper_app_name);
char* app_home_env = getenv((upper_app_name + "_USER_DIR").c_str()); /* Flawfinder: ignore */
auto app_home_env(LLStringUtil::getoptenv(upper_app_name + "_USER_DIR"));
if (app_home_env)
{
// user has specified own userappdir i.e. $SECONDLIFE_USER_DIR
mOSUserAppDir = app_home_env;
mOSUserAppDir = *app_home_env;
}
else
{

View File

@ -29,6 +29,7 @@
#include "lldir_solaris.h"
#include "llerror.h"
#include "llrand.h"
#include "llstring.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
@ -41,30 +42,28 @@
static std::string getCurrentUserHome(char* fallback)
{
// fwiw this exactly duplicates getCurrentUserHome() in lldir_linux.cpp...
// we should either derive both from LLDir_Posix or just axe Solaris.
const uid_t uid = getuid();
struct passwd *pw;
char *result_cstr = fallback;
pw = getpwuid(uid);
if ((pw != NULL) && (pw->pw_dir != NULL))
{
result_cstr = (char*) pw->pw_dir;
return pw->pw_dir;
}
LL_INFOS() << "Couldn't detect home directory from passwd - trying $HOME" << LL_ENDL;
auto home_env = LLStringUtil::getoptenv("HOME");
if (home_env)
{
return *home_env;
}
else
{
LL_INFOS() << "Couldn't detect home directory from passwd - trying $HOME" << LL_ENDL;
const char *const home_env = getenv("HOME"); /* Flawfinder: ignore */
if (home_env)
{
result_cstr = (char*) home_env;
}
else
{
LL_WARNS() << "Couldn't detect home directory! Falling back to " << fallback << LL_ENDL;
}
LL_WARNS() << "Couldn't detect home directory! Falling back to " << fallback << LL_ENDL;
return fallback;
}
return std::string(result_cstr);
}
@ -135,27 +134,15 @@ LLDir_Solaris::LLDir_Solaris()
//NOTE: Why force people to cd into the package directory?
// Look for SECONDLIFE env variable and use it, if set.
char *dcf = getenv("SECONDLIFE");
if(dcf != NULL){
(void)strcpy(path, dcf);
(void)strcat(path, "/bin"); //NOTE: make sure we point at the bin
mExecutableDir = strdup(path);
auto SECONDLIFE(LLDirUtil::getoptenv("SECONDLIFE"));
if(SECONDLIFE){
mExecutableDir = add(*SECONDLIFE, "bin"); //NOTE: make sure we point at the bin
}else{
// plunk a null at last '/' to get exec dir
char *s = execpath + strlen(execpath) -1;
while(*s != '/' && s != execpath){
--s;
}
if(s != execpath){
*s = (char)NULL;
mExecutableDir = strdup(execpath);
LL_INFOS() << "mExecutableDir = [" << mExecutableDir << "]" << LL_ENDL;
}
mExecutableDir = getDirName(execpath);
LL_INFOS() << "mExecutableDir = [" << mExecutableDir << "]" << LL_ENDL;
}
mLLPluginDir = mExecutableDir + mDirDelimiter + "llplugin";
mLLPluginDir = add(mExecutableDir, "llplugin");
// *TODO: don't use /tmp, use $HOME/.secondlife/tmp or something.
mTempDir = "/tmp";
@ -175,17 +162,18 @@ void LLDir_Solaris::initAppDirs(const std::string &app_name,
if (!app_read_only_data_dir.empty())
{
mAppRODataDir = app_read_only_data_dir;
mSkinBaseDir = add(mAppRODataDir, "skins");
}
mAppName = app_name;
std::string upper_app_name(app_name);
LLStringUtil::toUpper(upper_app_name);
char* app_home_env = getenv((upper_app_name + "_USER_DIR").c_str()); /* Flawfinder: ignore */
auto app_home_env(LLStringUtil::getoptenv(upper_app_name + "_USER_DIR"));
if (app_home_env)
{
// user has specified own userappdir i.e. $SECONDLIFE_USER_DIR
mOSUserAppDir = app_home_env;
mOSUserAppDir = *app_home_env;
}
else
{

View File

@ -30,7 +30,9 @@
#include "lldir_win32.h"
#include "llerror.h"
#include "llrand.h" // for gLindenLabRandomNumber
#include "llstring.h"
#include "stringize.h"
#include "llfile.h"
#include <shlobj.h>
#include <fstream>
@ -43,15 +45,87 @@
#define PACKVERSION(major,minor) MAKELONG(minor,major)
DWORD GetDllVersion(LPCTSTR lpszDllName);
namespace
{ // anonymous
enum class prst { INIT, OPEN, SKIP } state = prst::INIT;
// This is called so early that we can't count on static objects being
// properly constructed yet, so declare a pointer instead of an instance.
std::ofstream* prelogf = nullptr;
void prelog(const std::string& message)
{
boost::optional<std::string> prelog_name;
switch (state)
{
case prst::INIT:
// assume we failed, until we succeed
state = prst::SKIP;
prelog_name = LLStringUtil::getoptenv("PRELOG");
if (! prelog_name)
// no PRELOG variable set, carry on
return;
prelogf = new llofstream(*prelog_name, std::ios_base::app);
if (! (prelogf && prelogf->is_open()))
// can't complain to anybody; how?
return;
// got the log file open, cool!
state = prst::OPEN;
(*prelogf) << "========================================================================"
<< std::endl;
// fall through, don't break
case prst::OPEN:
(*prelogf) << message << std::endl;
break;
case prst::SKIP:
// either PRELOG isn't set, or we failed to open that pathname
break;
}
}
} // anonymous namespace
#define PRELOG(expression) prelog(STRINGIZE(expression))
LLDir_Win32::LLDir_Win32()
{
// set this first: used by append() and add() methods
mDirDelimiter = "\\";
WCHAR w_str[MAX_PATH];
// Application Data is where user settings go. We rely on $APPDATA being
// correct; in fact the VMP makes a point of setting it properly, since
// Windows itself botches the job for non-ASCII usernames (MAINT-8087).
mOSUserDir = ll_safe_string(getenv("APPDATA"));
// correct.
auto APPDATA = LLStringUtil::getoptenv("APPDATA");
if (APPDATA)
{
mOSUserDir = *APPDATA;
}
PRELOG("APPDATA='" << mOSUserDir << "'");
// On Windows, we could have received a plain-ASCII pathname in which
// non-ASCII characters have been munged to '?', or the pathname could
// have been badly encoded and decoded such that we now have garbage
// instead of a valid path. Check that mOSUserDir actually exists.
if (mOSUserDir.empty() || ! fileExists(mOSUserDir))
{
PRELOG("APPDATA does not exist");
//HRESULT okay = SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, w_str);
wchar_t *pwstr = NULL;
HRESULT okay = SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, NULL, &pwstr);
PRELOG("SHGetKnownFolderPath(FOLDERID_RoamingAppData) returned " << okay);
if (SUCCEEDED(okay) && pwstr)
{
// But of course, only update mOSUserDir if SHGetKnownFolderPath() works.
mOSUserDir = ll_convert_wide_to_string(pwstr);
// Not only that: update our environment so that child processes
// will see a reasonable value as well.
_wputenv_s(L"APPDATA", pwstr);
// SHGetKnownFolderPath() contract requires us to free pwstr
CoTaskMemFree(pwstr);
PRELOG("mOSUserDir='" << mOSUserDir << "'");
}
}
// We want cache files to go on the local disk, even if the
// user is on a network with a "roaming profile".
@ -61,9 +135,34 @@ LLDir_Win32::LLDir_Win32()
//
// We used to store the cache in AppData\Roaming, and the installer
// cleans up that version on upgrade. JC
mOSCacheDir = ll_safe_string(getenv("LOCALAPPDATA"));
auto LOCALAPPDATA = LLStringUtil::getoptenv("LOCALAPPDATA");
if (LOCALAPPDATA)
{
mOSCacheDir = *LOCALAPPDATA;
}
PRELOG("LOCALAPPDATA='" << mOSCacheDir << "'");
// Windows really does not deal well with pathnames containing non-ASCII
// characters. See above remarks about APPDATA.
if (mOSCacheDir.empty() || ! fileExists(mOSCacheDir))
{
PRELOG("LOCALAPPDATA does not exist");
//HRESULT okay = SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, w_str);
wchar_t *pwstr = NULL;
HRESULT okay = SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &pwstr);
PRELOG("SHGetKnownFolderPath(FOLDERID_LocalAppData) returned " << okay);
if (SUCCEEDED(okay) && pwstr)
{
// But of course, only update mOSCacheDir if SHGetKnownFolderPath() works.
mOSCacheDir = ll_convert_wide_to_string(pwstr);
// Update our environment so that child processes will see a
// reasonable value as well.
_wputenv_s(L"LOCALAPPDATA", pwstr);
// SHGetKnownFolderPath() contract requires us to free pwstr
CoTaskMemFree(pwstr);
PRELOG("mOSCacheDir='" << mOSCacheDir << "'");
}
}
WCHAR w_str[MAX_PATH];
if (GetTempPath(MAX_PATH, w_str))
{
if (wcslen(w_str)) /* Flawfinder: ignore */

View File

@ -3343,17 +3343,10 @@ S32 OSMessageBoxWin32(const std::string& text, const std::string& caption, U32 t
break;
}
// HACK! Doesn't properly handle wide strings!
// <FS:ND> Convert to wchar_t, then use MessageBoxW
// int retval_win = MessageBoxA(NULL, text.c_str(), caption.c_str(), uType);
llutf16string textW = utf8str_to_utf16str( text );
llutf16string captionW = utf8str_to_utf16str( caption );
int retval_win = MessageBoxW(NULL, textW.c_str(), captionW.c_str(), uType);
// </FS:ND>
int retval_win = MessageBoxW(NULL, // HWND
ll_convert_string_to_wide(text).c_str(),
ll_convert_string_to_wide(caption).c_str(),
uType);
S32 retval;
switch(retval_win)

View File

@ -27,43 +27,31 @@
#include "linden_common.h"
#include "llsdserialize.h"
#include "llfile.h"
#include "stringize.h"
#include "../llcontrol.h"
#include "../test/lltut.h"
#include <memory>
#include <vector>
namespace tut
{
struct control_group
{
LLControlGroup* mCG;
std::unique_ptr<LLControlGroup> mCG;
std::string mTestConfigDir;
std::string mTestConfigFile;
std::vector<std::string> mCleanups;
static bool mListenerFired;
control_group()
{
mCG = new LLControlGroup("foo");
mCG.reset(new LLControlGroup("foo"));
LLUUID random;
random.generate();
// generate temp dir
std::ostringstream oStr;
#ifdef LL_WINDOWS
char* tmp_dir = getenv("TMP");
if(tmp_dir)
{
oStr << tmp_dir << "/llcontrol-test-" << random << "/";
}
else
{
oStr << "c:/tmp/llcontrol-test-" << random << "/";
}
#else
oStr << "/tmp/llcontrol-test-" << random << "/";
#endif
mTestConfigDir = oStr.str();
mTestConfigDir = STRINGIZE(LLFile::tmpdir() << "llcontrol-test-" << random << "/");
mTestConfigFile = mTestConfigDir + "settings.xml";
LLFile::mkdir(mTestConfigDir);
LLSD config;
@ -76,7 +64,12 @@ namespace tut
~control_group()
{
//Remove test files
delete mCG;
for (auto filename : mCleanups)
{
LLFile::remove(filename);
}
LLFile::remove(mTestConfigFile);
LLFile::rmdir(mTestConfigDir);
}
void writeSettingsFile(const LLSD& config)
{
@ -118,6 +111,7 @@ namespace tut
ensure_equals("value of changed setting", mCG->getU32("TestSetting"), 13);
LLControlGroup test_cg("foo2");
std::string temp_test_file = (mTestConfigDir + "setting_llsd_temp.xml");
mCleanups.push_back(temp_test_file);
mCG->saveToFile(temp_test_file.c_str(), TRUE);
results = test_cg.loadFromFile(temp_test_file.c_str());
ensure("number of changed settings loaded", (results == 1));
@ -139,6 +133,7 @@ namespace tut
ensure_equals("value of changed setting", mCG->getU32("TestSetting"), 13);
LLControlGroup test_cg("foo3");
std::string temp_test_file = (mTestConfigDir + "setting_llsd_persist_temp.xml");
mCleanups.push_back(temp_test_file);
mCG->saveToFile(temp_test_file.c_str(), TRUE);
results = test_cg.loadFromFile(temp_test_file.c_str());
//If we haven't changed any settings, then we shouldn't have any settings to load
@ -153,7 +148,7 @@ namespace tut
ensure("number of settings", (results == 1));
mCG->getControl("TestSetting")->getSignal()->connect(boost::bind(&this->handleListenerTest));
mCG->setU32("TestSetting", 13);
ensure("listener fired on changed setting", mListenerFired);
ensure("listener fired on changed setting", mListenerFired);
}
}

View File

@ -1918,7 +1918,6 @@ if (WINDOWS)
kernel32
odbc32
odbccp32
ole32
oleaut32
shell32
Vfw32

View File

@ -18,8 +18,7 @@
;;
;; Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
;;
;; NSIS Unicode 2.46.5 or higher required
;; http://www.scratchpaper.com/
;; NSIS 3 or higher required for Unicode support
;;
;; Author: James Cook, TankMaster Finesmith, Don Kjer, Callum Prentice
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -27,6 +26,7 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Compiler flags
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Unicode true
SetOverwrite on # Overwrite files
SetCompress auto # Compress if saves space
SetCompressor /solid lzma # Compress whole installer as one block
@ -46,28 +46,33 @@ RequestExecutionLevel highest # match MULTIUSER_EXECUTIONLEVEL
;; (these files are in the same place as the nsi template but the python script generates a new nsi file in the
;; application directory so we have to add a path to these include files)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
!include "%%SOURCE%%\installers\windows\lang_en-us.nsi" # <FS:Ansariel> Make sure EN comes first as it will be default!
!include "%%SOURCE%%\installers\windows\lang_da.nsi"
;; Ansariel notes: "Under certain circumstances the installer will fall back
;; to the first defined (aka default) language version. So you want to include
;; en-us as first language file."
!include "%%SOURCE%%\installers\windows\lang_en-us.nsi"
# Danish and Polish no longer supported by the viewer itself
##!include "%%SOURCE%%\installers\windows\lang_da.nsi"
!include "%%SOURCE%%\installers\windows\lang_de.nsi"
!include "%%SOURCE%%\installers\windows\lang_es.nsi"
!include "%%SOURCE%%\installers\windows\lang_fr.nsi"
!include "%%SOURCE%%\installers\windows\lang_ja.nsi"
!include "%%SOURCE%%\installers\windows\lang_it.nsi"
!include "%%SOURCE%%\installers\windows\lang_pl.nsi"
##!include "%%SOURCE%%\installers\windows\lang_pl.nsi"
!include "%%SOURCE%%\installers\windows\lang_pt-br.nsi"
!include "%%SOURCE%%\installers\windows\lang_ru.nsi"
!include "%%SOURCE%%\installers\windows\lang_tr.nsi"
!include "%%SOURCE%%\installers\windows\lang_zh.nsi"
# *TODO: Move these into the language files themselves
LangString LanguageCode ${LANG_DANISH} "da"
##LangString LanguageCode ${LANG_DANISH} "da"
LangString LanguageCode ${LANG_GERMAN} "de"
LangString LanguageCode ${LANG_ENGLISH} "en"
LangString LanguageCode ${LANG_SPANISH} "es"
LangString LanguageCode ${LANG_FRENCH} "fr"
LangString LanguageCode ${LANG_JAPANESE} "ja"
LangString LanguageCode ${LANG_ITALIAN} "it"
LangString LanguageCode ${LANG_POLISH} "pl"
##LangString LanguageCode ${LANG_POLISH} "pl"
LangString LanguageCode ${LANG_PORTUGUESEBR} "pt"
LangString LanguageCode ${LANG_RUSSIAN} "ru"
LangString LanguageCode ${LANG_TURKISH} "tr"
@ -114,12 +119,14 @@ SetOverwrite on # Overwrite files by default
# should make MultiUser.nsh initialization read existing INSTDIR from registry
!define MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_KEY "${INSTNAME_KEY}"
!define MULTIUSER_INSTALLMODE_INSTDIR_REGISTRY_VALUENAME ""
# should make MultiUser.nsh initialization write $MultiUser.InstallMode to registry
!define MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_KEY "${INSTNAME_KEY}"
!define MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_VALUENAME "InstallMode"
# Don't set MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_KEY and
# MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_VALUENAME to cause the installer to
# write $MultiUser.InstallMode to the registry, because when the user installs
# multiple viewers with the same channel (same ${INSTNAME}, hence same
# ${INSTNAME_KEY}), the registry entry is overwritten. Instead we'll write a
# little file into the install directory -- see .onInstSuccess and un.onInit.
!include MultiUser.nsh
!include MUI2.nsh
!define MUI_BGCOLOR FFFFFF
!insertmacro MUI_FUNCTION_GUIINIT
@ -242,8 +249,6 @@ lbl_configure_default_lang:
# </FS:Ansariel>
StrCmp $SKIP_DIALOGS "true" lbl_return
# <FS:Ansariel> Commented out; Warning in build log about not being used
;lbl_build_menu:
Push ""
# Use separate file so labels can be UTF-16 but we can still merge changes into this ASCII file. JC
!include "%%SOURCE%%\installers\windows\language_menu.nsi"
@ -267,7 +272,21 @@ FunctionEnd
;; Prep Uninstaller Section
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Function un.onInit
!insertmacro MULTIUSER_UNINIT
# Save $INSTDIR -- it appears to have the correct value before
# MULTIUSER_UNINIT, but then gets munged by MULTIUSER_UNINIT?!
Push $INSTDIR
!insertmacro MULTIUSER_UNINIT
Pop $INSTDIR
# Now read InstallMode.txt from $INSTDIR
Push $0
ClearErrors
FileOpen $0 "$INSTDIR\InstallMode.txt" r
IfErrors skipread
FileRead $0 $MultiUser.InstallMode
FileClose $0
skipread:
Pop $0
%%ENGAGEREGISTRY%%
@ -276,10 +295,10 @@ Function un.onInit
IfErrors lbl_end
StrCpy $LANGUAGE $0
lbl_end:
Return
# Does MultiUser.nsh init read back
# MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_KEY into $MultiUser.InstallMode?
## MessageBox MB_OK "After restoring:$\n$$INSTDIR = '$INSTDIR'$\n$$MultiUser.InstallMode = '$MultiUser.InstallMode'$\n$$LANGUAGE = '$LANGUAGE'"
Return
FunctionEnd
@ -474,8 +493,10 @@ StrCpy $INSTSHORTCUT "${SHORTCUT}"
# MULTIUSER_INSTALLMODE_DEFAULT_REGISTRY_VALUENAME
# Couln't get NSIS to expand $MultiUser.InstallMode into the function name at Call time
${If} $MultiUser.InstallMode == 'AllUsers'
##MessageBox MB_OK "Uninstalling for all users"
Call un.MultiUser.InstallMode.AllUsers
${Else}
##MessageBox MB_OK "Uninstalling for current user"
Call un.MultiUser.InstallMode.CurrentUser
${EndIf}
@ -688,6 +709,9 @@ Function un.ProgramFiles
# This placeholder is replaced by the complete list of files to uninstall by viewer_manifest.py
%%DELETE_FILES%%
# our InstallMode.txt
Delete "$INSTDIR\InstallMode.txt"
# Optional/obsolete files. Delete won't fail if they don't exist.
Delete "$INSTDIR\autorun.bat"
Delete "$INSTDIR\dronesettings.ini"
@ -737,7 +761,12 @@ FunctionEnd
;; After install completes, launch app
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Function .onInstSuccess
Call CheckWindowsServPack # Warn if not on the latest SP before asking to launch.
Push $0
FileOpen $0 "$INSTDIR\InstallMode.txt" w
# No newline -- this is for our use, not for users to read.
FileWrite $0 "$MultiUser.InstallMode"
FileClose $0
Pop $0
# <FS:Ansariel> Disable VMP
#Push $R0
#Push $0
@ -760,24 +789,21 @@ Function .onInstSuccess
#Pop $0
#Pop $R0
# </FS:Ansariel>
Push $R0 # Option value, unused#
# <FS:PP> Disable autorun
# StrCmp $SKIP_AUTORUN "true" +2;
# Assumes SetOutPath $INSTDIR
# Exec '"$WINDIR\explorer.exe" "$INSTDIR\$INSTEXE"'
# Pop $R0
StrCmp $SKIP_DIALOGS "true" label_launch
${GetOptions} $COMMANDLINE "/AUTOSTART" $R0
# If parameter was there (no error) just launch
# Otherwise ask
IfErrors label_ask_launch label_launch
Call CheckWindowsServPack # Warn if not on the latest SP before asking to launch.
# <FS:PP> Disable autorun
#StrCmp $SKIP_AUTORUN "true" +2;
StrCmp $SKIP_DIALOGS "true" label_launch
${GetOptions} $COMMANDLINE "/AUTOSTART" $R0
# If parameter was there (no error) just launch
# Otherwise ask
IfErrors label_ask_launch label_launch
label_ask_launch:
# Don't launch by default when silent
IfSilent label_no_launch
MessageBox MB_YESNO $(InstSuccesssQuestion) \
IDYES label_launch IDNO label_no_launch
# Don't launch by default when silent
IfSilent label_no_launch
MessageBox MB_YESNO $(InstSuccesssQuestion) IDYES label_launch IDNO label_no_launch
label_launch:
# Assumes SetOutPath $INSTDIR
@ -796,10 +822,9 @@ label_launch:
# string because it must decompose into separate command-line tokens.
# <FS:Ansariel> No updater, thanks!
# Exec '"$INSTDIR\$INSTEXE" precheck "$INSTDIR\$VIEWER_EXE" $SHORTCUT_LANG_PARAM'
Exec '"$WINDIR\explorer.exe" "$INSTDIR\$INSTSHORTCUT.lnk"'
Exec '"$WINDIR\explorer.exe" "$INSTDIR\$INSTSHORTCUT.lnk"'
label_no_launch:
Pop $R0
# </FS:PP>
# </FS:PP>
FunctionEnd
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View File

@ -674,7 +674,9 @@ bool LLAppViewerWin32::init()
std::string build_data_fname(
gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "build_data.json"));
std::ifstream inf(build_data_fname.c_str());
// Use llifstream instead of std::ifstream because LL_PATH_EXECUTABLE
// could contain non-ASCII characters, which std::ifstream doesn't handle.
llifstream inf(build_data_fname.c_str());
if (! inf.is_open())
{
LL_WARNS() << "Can't initialize BugSplat, can't read '" << build_data_fname

View File

@ -31,6 +31,7 @@
#include "llui.h"
#include "llprocess.h"
#include "llsdutil.h"
#include "llstring.h"
#include <boost/foreach.hpp>
// static
@ -206,12 +207,12 @@ std::string LLExternalEditor::findCommand(
cmd = LLUI::sSettingGroups["config"]->getString(sSetting);
LL_INFOS() << "Using setting" << LL_ENDL;
}
else // otherwise use the path specified by the environment variable
else // otherwise use the path specified by the environment variable
{
char* env_var_val = getenv(env_var.c_str());
auto env_var_val(LLStringUtil::getoptenv(env_var));
if (env_var_val)
{
cmd = env_var_val;
cmd = *env_var_val;
LL_INFOS() << "Using env var " << env_var << LL_ENDL;
}
}

View File

@ -33,6 +33,7 @@
#include "llimagepng.h"
#include "llsdserialize.h"
#include "llstring.h"
// newview
#include "llpanelprofile.h" // for getProfileURL(). FIXME: move the method to LLAvatarActions
@ -264,6 +265,5 @@ void LLWebProfile::reportImageUploadStatus(bool ok)
std::string LLWebProfile::getAuthCookie()
{
// This is needed to test image uploads on Linux viewer built with OpenSSL 1.0.0 (0.9.8 works fine).
const char* debug_cookie = getenv("LL_SNAPSHOT_COOKIE");
return debug_cookie ? debug_cookie : sAuthCookie;
return LLStringUtil::getenv("LL_SNAPSHOT_COOKIE", sAuthCookie);
}

View File

@ -561,6 +561,7 @@ class WindowsManifest(ViewerManifest):
#with self.prefix(src=os.path.join(pkgdir, "VMP")):
# include the compiled launcher scripts so that it gets included in the file_list
# self.path('SLVersionChecker.exe')
# self.path('nextviewer.bat')
#with self.prefix(dst="vmp_icons"):
# with self.prefix(src=self.icon_path()):
@ -956,12 +957,10 @@ class WindowsManifest(ViewerManifest):
# ):
# self.sign(exe)
# We use the Unicode version of NSIS, available from
# http://www.scratchpaper.com/
# Check two paths, one for Program Files, and one for Program Files (x86).
# Yay 64bit windows.
for ProgramFiles in 'ProgramFiles', 'ProgramFiles(x86)':
NSIS_path = os.path.expandvars(r'${%s}\NSIS\Unicode\makensis.exe' % ProgramFiles)
NSIS_path = os.path.expandvars(r'${%s}\NSIS\makensis.exe' % ProgramFiles)
if os.path.exists(NSIS_path):
break
installer_created=False

View File

@ -95,7 +95,6 @@ target_link_libraries(windows-crash-logger
${GOOGLE_PERFTOOLS_LIBRARIES}
user32
gdi32
ole32
oleaut32
wininet
Wldap32