Merge branch 'master' into linux_fltk

master
Nicky 2021-12-21 00:39:10 +01:00
commit 0953b6b646
488 changed files with 18735 additions and 13905 deletions

1
.gitignore vendored
View File

@ -58,6 +58,7 @@ indra/newview/search_history.txt
indra/newview/teleport_history.txt
indra/newview/typed_locations.txt
indra/newview/vivox-runtime
indra/newview/skins/default/html/common/equirectangular/js
indra/server-linux-*
indra/temp
indra/test/linden_file.dat

View File

@ -14,7 +14,7 @@ build_docs = true
build_Linux_Doxygen = true
# Need viewer-build-variables as well as other shared repositories
buildscripts_shared_more_NAMEs="build_secrets build_variables"
buildscripts_shared_more_NAMEs="build_secrets build_variables git_hooks"
################################################################
#### Examples of how to set the viewer_channel ####

File diff suppressed because it is too large Load Diff

View File

@ -16,6 +16,29 @@
# * The special style in which python is invoked is intentional to permit
# use of a native python install on windows - which requires paths in DOS form
retry_cmd()
{
max_attempts="$1"; shift
initial_wait="$1"; shift
attempt_num=1
echo "trying" "$@"
until "$@"
do
if ((attempt_num==max_attempts))
then
echo "Last attempt $attempt_num failed"
return 1
else
wait_time=$(($attempt_num*$initial_wait))
echo "Attempt $attempt_num failed. Trying again in $wait_time seconds..."
sleep $wait_time
attempt_num=$(($attempt_num+1))
fi
done
echo "succeeded"
return 0
}
build_dir_Darwin()
{
echo build-darwin-x86_64
@ -275,6 +298,22 @@ python_cmd "$helpers/codeticket.py" addinput "Viewer Channel" "${viewer_channel}
initialize_version # provided by buildscripts build.sh; sets version id
begin_section "coding policy check"
# On our TC Windows build hosts, the GitPython library underlying our
# coding_policy_git.py script fails to run git for reasons we have not tried
# to diagnose. Clearly git works fine on those hosts, or we would never get
# this far. Running coding policy checks on one platform *should* suffice...
if [[ "$arch" == "Darwin" ]]
then
# install the git-hooks dependencies
pip install -r "$(native_path "$git_hooks_checkout/requirements.txt")" || \
fatal "pip install git-hooks failed"
# validate the branch we're about to build
python_cmd "$git_hooks_checkout/coding_policy_git.py" --all_files || \
fatal "coding policy check failed"
fi
end_section "coding policy check"
# Now run the build
succeeded=true
last_built_variant=
@ -444,7 +483,7 @@ then
succeeded=$build_coverity
else
# Upload base package.
python_cmd "$helpers/codeticket.py" addoutput Installer "$package" \
retry_cmd 4 30 python_cmd "$helpers/codeticket.py" addoutput Installer "$package" \
|| fatal "Upload of installer failed"
wait_for_codeticket
@ -454,7 +493,7 @@ then
package=$(installer_$arch "$package_id")
if [ x"$package" != x ]
then
python_cmd "$helpers/codeticket.py" addoutput "Installer $package_id" "$package" \
retry_cmd 4 30 python_cmd "$helpers/codeticket.py" addoutput "Installer $package_id" "$package" \
|| fatal "Upload of installer $package_id failed"
wait_for_codeticket
else
@ -468,7 +507,7 @@ then
if [ "${RELEASE_CRASH_REPORTING:-}" != "OFF" ]
then
# Upload crash reporter file
python_cmd "$helpers/codeticket.py" addoutput "Symbolfile" "$VIEWER_SYMBOL_FILE" \
retry_cmd 4 30 python_cmd "$helpers/codeticket.py" addoutput "Symbolfile" "$VIEWER_SYMBOL_FILE" \
|| fatal "Upload of symbolfile failed"
wait_for_codeticket
fi
@ -478,10 +517,7 @@ then
if [ -r "$build_dir/llphysicsextensions_package" ]
then
llphysicsextensions_package=$(cat $build_dir/llphysicsextensions_package)
# This next upload is a frequent failure; see if giving the last one some time helps
# JJ is making changes to Codeticket that we hope will eliminate this failure soon
sleep 300
python_cmd "$helpers/codeticket.py" addoutput "Physics Extensions Package" "$llphysicsextensions_package" --private \
retry_cmd 4 30 python_cmd "$helpers/codeticket.py" addoutput "Physics Extensions Package" "$llphysicsextensions_package" --private \
|| fatal "Upload of physics extensions package failed"
fi
fi

18
debian/changelog vendored
View File

@ -1,18 +0,0 @@
secondlife-viewer (0.3) unstable; urgency=low
* Initial debian configuration
-- Don Kjer <don@lindenlab.com> Wed, 04 Jul 2012 00:43:03 +0000
secondlife-viewer (0.2) unstable; urgency=low
* Adding default LSB headers for squeeze
-- Tyler Kohler <tyler@lindenlab.com> Thu, 24 Mar 2011 09:43:36 -0700
secondlife-viewer (0.1) unstable; urgency=low
* Cloned from debian package skeleton.
-- Lex Linden <lex@lindenlab.com> Mon, 20 Sep 2010 08:01:59 -0700

1
debian/compat vendored
View File

@ -1 +0,0 @@
5

16
debian/control vendored
View File

@ -1,16 +0,0 @@
Source: secondlife-viewer
Section: unknown
Priority: extra
Maintainer: Don Linden <don@lindenlab.com>
Build-Depends: debhelper (>= 5)
Homepage: http://secondlife.com
Standards-Version: 3.7.2
Package: secondlife-viewer
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends},
ia32-libs,
ia32-libs-gtk
Description: Second Life Viewer
Second Life is an online virtual world developed by Linden Lab.

32
debian/copyright vendored
View File

@ -1,32 +0,0 @@
Second Life Viewer Copyright: 2000-2012 Linden Research, Inc.
License:
3Dconnexion SDK Copyright (C) 1992-2009 3Dconnexion
APR Copyright (C) 2011 The Apache Software Foundation
Collada DOM Copyright 2006 Sony Computer Entertainment Inc.
cURL Copyright (C) 1996-2010, Daniel Stenberg, (daniel@haxx.se)
DBus/dbus-glib Copyright (C) 2002, 2003 CodeFactory AB / Copyright (C) 2003, 2004 Red Hat, Inc.
expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd.
FreeType Copyright (C) 1996-2002, 2006 David Turner, Robert Wilhelm, and Werner Lemberg.
GL Copyright (C) 1999-2004 Brian Paul.
GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University and David Luebke, Brenden Schubert, University of Virginia.
google-perftools Copyright (c) 2005, Google Inc.
Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited.
jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW)
jpeglib Copyright (C) 1991-1998, Thomas G. Lane.
ogg/vorbis Copyright (C) 2002, Xiphophorus
OpenSSL Copyright (C) 1998-2008 The OpenSSL Project.
PCRE Copyright (c) 1997-2012 University of Cambridge
SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
xmlrpc-epi Copyright (C) 2000 Epinions, Inc.
zlib Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler.
Second Life Viewer uses Havok (TM) Physics. (c)Copyright 1999-2010 Havok.com Inc. (and its Licensors). All Rights Reserved. See www.havok.com for details.
This software contains source code provided by NVIDIA Corporation.
All rights reserved. See licenses.txt for details.
Voice chat Audio coding: Polycom(R) Siren14(TM) (ITU-T Rec. G.722.1 Annex C)

43
debian/postinst vendored
View File

@ -1,43 +0,0 @@
#!/bin/sh
# postinst script for secondlife-viewer
#
# Delete this file if you don't need it.
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <postinst> `configure' <most-recently-configured-version>
# * <old-postinst> `abort-upgrade' <new version>
# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
# <new-version>
# * <postinst> `abort-remove'
# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
# <failed-install-package> <version> `removing'
# <conflicting-package> <version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package
case "$1" in
configure)
;;
abort-upgrade|abort-remove|abort-deconfigure)
;;
*)
echo "postinst called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts. Don't delete this!
#DEBHELPER#
exit 0

41
debian/postrm vendored
View File

@ -1,41 +0,0 @@
#!/bin/sh
# postrm script for secondlife-viewer
#
# Delete this file if you don't need it.
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <postrm> `remove'
# * <postrm> `purge'
# * <old-postrm> `upgrade' <new-version>
# * <new-postrm> `failed-upgrade' <old-version>
# * <new-postrm> `abort-install'
# * <new-postrm> `abort-install' <old-version>
# * <new-postrm> `abort-upgrade' <old-version>
# * <disappearer's-postrm> `disappear' <overwriter>
# <overwriter-version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package
case "$1" in
purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
;;
*)
echo "postrm called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts. Don't delete this!
#DEBHELPER#
exit 0

39
debian/preinst vendored
View File

@ -1,39 +0,0 @@
#!/bin/sh
# preinst script for secondlife-viewer
#
# Delete this file if you don't need it.
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <new-preinst> `install'
# * <new-preinst> `install' <old-version>
# * <new-preinst> `upgrade' <old-version>
# * <old-preinst> `abort-upgrade' <new-version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package
case "$1" in
install|upgrade)
;;
abort-upgrade)
;;
*)
echo "preinst called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts. Don't delete this!
#DEBHELPER#
exit 0

42
debian/prerm vendored
View File

@ -1,42 +0,0 @@
#!/bin/sh
# prerm script for secondlife-viewer
#
# Delete this file if you don't need it.
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <prerm> `remove'
# * <old-prerm> `upgrade' <new-version>
# * <new-prerm> `failed-upgrade' <old-version>
# * <conflictor's-prerm> `remove' `in-favour' <package> <new-version>
# * <deconfigured's-prerm> `deconfigure' `in-favour'
# <package-being-installed> <version> `removing'
# <conflicting-package> <version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package
case "$1" in
remove|upgrade|deconfigure)
;;
failed-upgrade)
;;
*)
echo "prerm called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts. Don't delete this!
#DEBHELPER#
exit 0

118
debian/rules vendored
View File

@ -1,118 +0,0 @@
#!/usr/bin/make -f
# -*- makefile -*-
# Sample debian/rules that uses debhelper.
# This file was originally written by Joey Hess and Craig Small.
# As a special exception, when this file is copied by dh-make into a
# dh-make output file, you may use that output file without restriction.
# This special exception was added by Craig Small in version 0.37 of dh-make.
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
BASEDIR=opt/linden
VIEWER_PKG=secondlife-viewer
VIEWER_PACKAGEDIR=build-linux-i686/newview/packaged
VIEWER_DESTDIR=$(CURDIR)/debian/$(VIEWER_PKG)
VIEWER_VERSION:=$(shell dpkg-parsechangelog | grep ^Version | sed 's/^Version: //')
VIEWER_INSTALLDIR:=$(BASEDIR)/viewer/SecondLife-i686-$(VIEWER_VERSION)
configure: configure-stamp
configure-stamp:
dh_testdir
# Add here commands to configure the package.
touch configure-stamp
build: build-stamp
build-stamp: configure-stamp
dh_testdir
# Add here commands to compile the package.
#$(MAKE)
#docbook-to-man debian/secondlife-viewer.sgml > secondlife-viewer.1
touch $@
clean:
dh_testdir
dh_testroot
rm -f build-stamp configure-stamp
# Add here commands to clean up after the build process.
#-$(MAKE) clean
dh_clean
install: build
dh_testdir
dh_testroot
dh_clean -k
dh_installdirs
# Add here commands to install the package into debian/secondlife-viewer.
for file in $$(find $(VIEWER_PACKAGEDIR) -type f -o -type l | sed 's~$(VIEWER_PACKAGEDIR)/~~'); do \
# create containing directory \
install -v -m 755 -o root -g root -d "$$(dirname "$(VIEWER_DESTDIR)/$(VIEWER_INSTALLDIR)/$$file")"; \
PERM=644; \
if [ -x "$(VIEWER_PACKAGEDIR)/$$file" ]; then \
PERM=755; \
fi; \
if [ -L "$(VIEWER_PACKAGEDIR)/$$file" ]; then \
REAL="$$( readlink -f $(VIEWER_PACKAGEDIR)/$$file )"; \
RELATIVE="$$( echo $$REAL | sed 's~$(CURDIR)/$(VIEWER_PACKAGEDIR)/~~' )"; \
echo dh_link -p $(VIEWER_PKG) "$(VIEWER_INSTALLDIR)/$$RELATIVE" "$(VIEWER_INSTALLDIR)/$$file" ; \
dh_link -p $(VIEWER_PKG) "$(VIEWER_INSTALLDIR)/$$RELATIVE" "$(VIEWER_INSTALLDIR)/$$file" ; \
else \
install -v -m $$PERM -o root -g root "$(VIEWER_PACKAGEDIR)/$$file" "$(VIEWER_DESTDIR)/$(VIEWER_INSTALLDIR)/$$file"; \
fi; \
done
dh_link -p $(VIEWER_PKG) /$(VIEWER_INSTALLDIR)/secondlife /usr/bin/secondlife
dh_link -p $(VIEWER_PKG) $(BASEDIR)/viewer/SecondLife-i686-$(VIEWER_VERSION) $(BASEDIR)/viewer/SecondLife
# Build architecture-independent files here.
binary-indep: build install
# We have nothing to do by default.
# Build architecture-dependent files here.
binary-arch: build install
dh_testdir
dh_testroot
dh_installchangelogs
dh_installdocs
dh_installexamples
# dh_install
# dh_installmenu
# dh_installdebconf
# dh_installlogrotate
# dh_installemacsen
# dh_installpam
# dh_installmime
# dh_python
# To add an init script, uncomment this line and edit debian/init.d and
# customize debian/secondlife-viewer.default to suit your needs.
# dh_installinit
# To add cron jobs, uncomment this line and make a crontab file named
# debian/cron.d, and it will be installed in /etc/cron.d/
# dh_installcron
# dh_installinfo
dh_installman
dh_link
# dh_strip
dh_compress
# dh_fixperms
# dh_perl
# dh_makeshlibs
dh_installdeb
# dh_shlibdeps
dh_gencontrol
dh_md5sums
dh_builddeb
binary: binary-indep binary-arch
.PHONY: build clean binary-indep binary-arch binary install configure

View File

@ -1,8 +0,0 @@
# Linden packages install in opt/linden
secondlife-viewer: dir-or-file-in-opt
secondlife-viewer: section-is-dh_make-template
secondlife-viewer: binary-without-manpage
secondlife-viewer: maintainer-script-empty postrm
secondlife-viewer: maintainer-script-empty preinst
secondlife-viewer: maintainer-script-empty prerm
secondlife-viewer: unstripped-binary-or-object

View File

@ -228,8 +228,15 @@ Ansariel Hiller
SL-13364
SL-13858
SL-13697
SL-14939
SL-14940
SL-14941
SL-13395
SL-3136
SL-15200
SL-15226
SL-15227
SL-15398
Aralara Rajal
Arare Chantilly
CHUIBUG-191
@ -272,6 +279,7 @@ Beq Janus
SL-13583
SL-14766
SL-14927
SL-11300
Beth Walcher
Bezilon Kasei
Biancaluce Robbiani
@ -812,6 +820,7 @@ Jonathan Yap
STORM-2142
STORM-2145
SL-10089
BUG-229818
Kadah Coba
STORM-1060
STORM-1843

BIN
doc/sl-logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

@ -154,18 +154,6 @@ if (USE_BUGSPLAT)
endif (BUGSPLAT_DB)
else (USE_BUGSPLAT)
message(STATUS "Not building with BugSplat")
if (LINUX)
add_subdirectory(${VIEWER_PREFIX}linux_crash_logger)
#<FS:TS> Huh? Where'd that target come from?
#add_dependencies(viewer linux-crash-logger-strip-target)
elseif (DARWIN)
add_subdirectory(${VIEWER_PREFIX}mac_crash_logger)
add_dependencies(viewer mac-crash-logger)
elseif (WINDOWS)
add_subdirectory(${VIEWER_PREFIX}win_crash_logger)
# add_dependencies(viewer windows-setup windows-crash-logger)
add_dependencies(viewer windows-crash-logger)
endif (LINUX)
endif (USE_BUGSPLAT)
add_subdirectory(${VIEWER_PREFIX}newview)

View File

@ -82,7 +82,7 @@ if (WINDOWS)
# CP changed to only append the flag for 32bit builds - on 64bit builds,
# locally at least, the build output is spammed with 1000s of 'D9002'
# warnings about this switch being ignored.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
# <FS:ND> Remove this, it's no option to cl.exe and causes a massive amount of warnings.
#if( ADDRESS_SIZE EQUAL 32 )
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /p:PreferredToolArchitecture=x64")
@ -165,6 +165,11 @@ endif (WINDOWS)
if (LINUX)
set(CMAKE_SKIP_RPATH TRUE)
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 10.0.0 )
message( FATAL_ERROR "GCC greater 9.4.0 is not supported. Recompile boost for support of GCC 10.0.0 and up." )
endif()
# <FS:ND/>
# And another hack for FORTIFY_SOURCE. Some distributions (for example Gentoo) define FORTIFY_SOURCE by default.
# Check if this is the case, if yes, do not define it again.

View File

@ -24,7 +24,7 @@ elseif (DARWIN)
message(FATAL_ERROR "AppKit not found")
endif()
FIND_LIBRARY(CEF_LIBRARY "Chromium Embedded Framework" ${ARCH_PREBUILT_DIRS_RELEASE})
set(CEF_LIBRARY "'${ARCH_PREBUILT_DIRS_RELEASE}/Chromium\ Embedded\ Framework.framework'")
if (NOT CEF_LIBRARY)
message(FATAL_ERROR "CEF not found")
endif()
@ -33,7 +33,7 @@ elseif (DARWIN)
${ARCH_PREBUILT_DIRS_RELEASE}/libcef_dll_wrapper.a
${ARCH_PREBUILT_DIRS_RELEASE}/libdullahan.a
${APPKIT_LIBRARY}
${CEF_LIBRARY}
"-F ${CEF_LIBRARY}"
)
elseif (LINUX)

View File

@ -30,7 +30,6 @@ set(cmake_SOURCE_FILES
FindBerkeleyDB.cmake
FindFMODSTUDIO.cmake
FindGLH.cmake
FindGoogleBreakpad.cmake
FindHUNSPELL.cmake
FindJsonCpp.cmake
FindNDOF.cmake
@ -45,7 +44,6 @@ set(cmake_SOURCE_FILES
GLH.cmake
GLOD.cmake
## GStreamer010Plugin.cmake
GoogleBreakpad.cmake
GoogleMock.cmake
Growl.cmake
Havok.cmake

View File

@ -56,8 +56,6 @@ if(WINDOWS)
libapr-1.dll
libaprutil-1.dll
libapriconv-1.dll
ssleay32.dll
libeay32.dll
nghttp2.dll
glod.dll
libhunspell.dll
@ -70,6 +68,15 @@ if(WINDOWS)
endif (NOT USE_KDU)
# </FS:Ansariel>
# OpenSSL
if(ADDRESS_SIZE EQUAL 64)
set(release_files ${release_files} libcrypto-1_1-x64.dll)
set(release_files ${release_files} libssl-1_1-x64.dll)
else(ADDRESS_SIZE EQUAL 64)
set(release_files ${release_files} libcrypto-1_1.dll)
set(release_files ${release_files} libssl-1_1.dll)
endif(ADDRESS_SIZE EQUAL 64)
# Filenames are different for 32/64 bit BugSplat file and we don't
# have any control over them so need to branch.
if (USE_BUGSPLAT)
@ -190,7 +197,6 @@ elseif(DARWIN)
libapr-1.dylib
libaprutil-1.0.dylib
libaprutil-1.dylib
libexception_handler.dylib
${EXPAT_COPY}
libGLOD.dylib
libhunspell-1.3.0.dylib

View File

@ -0,0 +1,5 @@
# -*- cmake -*-
use_prebuilt_binary(cubemaptoequirectangular)
# Main JS file
#configure_file("${AUTOBUILD_INSTALL_DIR}/js/CubemapToEquirectangular.js" "${CMAKE_SOURCE_DIR}/newview/skins/default/html/common/equirectangular/js/CubemapToEquirectangular.js" COPYONLY)

View File

@ -1,44 +0,0 @@
# -*- cmake -*-
# - Find Google BreakPad
# Find the Google BreakPad includes and library
# This module defines
# BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR, where to find exception_handler.h, etc.
# BREAKPAD_EXCEPTION_HANDLER_LIBRARIES, the libraries needed to use Google BreakPad.
# BREAKPAD_EXCEPTION_HANDLER_FOUND, If false, do not try to use Google BreakPad.
# also defined, but not for general use are
# BREAKPAD_EXCEPTION_HANDLER_LIBRARY, where to find the Google BreakPad library.
# LL code uses "google_breakpad" path prefix, while google breakpad headers don't use a prefix. Find and add both paths to the correct variable.
FIND_PATH(BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR google_breakpad/exception_handler.h)
FIND_PATH(BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIRS exception_handler.h PATH_SUFFIXES google_breakpad)
SET(BREAKPAD_INCLUDE_DIRECTORIES ${BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR} ${BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIRS})
SET(BREAKPAD_EXCEPTION_HANDLER_NAMES ${BREAKPAD_EXCEPTION_HANDLER_NAMES} breakpad_client)
FIND_LIBRARY(BREAKPAD_EXCEPTION_HANDLER_LIBRARY
NAMES ${BREAKPAD_EXCEPTION_HANDLER_NAMES}
)
IF (BREAKPAD_EXCEPTION_HANDLER_LIBRARY AND BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR)
SET(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES ${BREAKPAD_EXCEPTION_HANDLER_LIBRARY})
SET(BREAKPAD_EXCEPTION_HANDLER_FOUND "YES")
ELSE (BREAKPAD_EXCEPTION_HANDLER_LIBRARY AND BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR)
SET(BREAKPAD_EXCEPTION_HANDLER_FOUND "NO")
ENDIF (BREAKPAD_EXCEPTION_HANDLER_LIBRARY AND BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR)
IF (BREAKPAD_EXCEPTION_HANDLER_FOUND)
IF (NOT BREAKPAD_EXCEPTION_HANDLER_FIND_QUIETLY)
MESSAGE(STATUS "Found Google BreakPad: ${BREAKPAD_EXCEPTION_HANDLER_LIBRARIES}")
MESSAGE(STATUS "Found Google BreakPad headers in: ${BREAKPAD_INCLUDE_DIRECTORIES}")
ENDIF (NOT BREAKPAD_EXCEPTION_HANDLER_FIND_QUIETLY)
ELSE (BREAKPAD_EXCEPTION_HANDLER_FOUND)
IF (BREAKPAD_EXCEPTION_HANDLER_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find Google BreakPad library")
ENDIF (BREAKPAD_EXCEPTION_HANDLER_FIND_REQUIRED)
ENDIF (BREAKPAD_EXCEPTION_HANDLER_FOUND)
MARK_AS_ADVANCED(
BREAKPAD_EXCEPTION_HANDLER_LIBRARY
BREAKPAD_EXCEPTION_HANDLER_INCLUDE_DIR
)

View File

@ -1,22 +0,0 @@
# -*- cmake -*-
include(Prebuilt)
#if (USESYSTEMLIBS)
# set(BREAKPAD_EXCEPTION_HANDLER_FIND_REQUIRED ON)
# include(FindGoogleBreakpad)
#else (USESYSTEMLIBS)
use_prebuilt_binary(google_breakpad)
if (DARWIN)
set(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES exception_handler)
endif (DARWIN)
if (LINUX)
set(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES breakpad_client)
endif (LINUX)
if (WINDOWS)
set(BREAKPAD_EXCEPTION_HANDLER_LIBRARIES exception_handler crash_generation_client crash_generation_server common)
endif (WINDOWS)
# yes, this does look dumb, no, it's not incorrect
#
set(BREAKPAD_INCLUDE_DIRECTORIES "${LIBS_PREBUILT_DIR}/include/google_breakpad" "${LIBS_PREBUILT_DIR}/include/google_breakpad/google_breakpad")
#endif (USESYSTEMLIBS)

View File

@ -0,0 +1,5 @@
# -*- cmake -*-
use_prebuilt_binary(jpegencoderbasic)
# Main JS file
#configure_file("${AUTOBUILD_INSTALL_DIR}/js/jpeg_encoder_basic.js" "${CMAKE_SOURCE_DIR}/newview/skins/default/html/common/equirectangular/js/jpeg_encoder_basic.js" COPYONLY)

View File

@ -9,7 +9,7 @@ if (USESYSTEMLIBS)
else (USESYSTEMLIBS)
use_prebuilt_binary(openssl)
if (WINDOWS)
set(OPENSSL_LIBRARIES ssleay32 libeay32)
set(OPENSSL_LIBRARIES libssl libcrypto)
else (WINDOWS)
set(OPENSSL_LIBRARIES ssl crypto)
endif (WINDOWS)
@ -17,7 +17,7 @@ else (USESYSTEMLIBS)
endif (USESYSTEMLIBS)
if (LINUX)
set(CRYPTO_LIBRARIES crypto dl)
set(CRYPTO_LIBRARIES crypto dl pthread)
elseif (DARWIN)
set(CRYPTO_LIBRARIES crypto)
endif (LINUX)

View File

@ -0,0 +1,8 @@
# -*- cmake -*-
use_prebuilt_binary(threejs)
# Main three.js file
#configure_file("${AUTOBUILD_INSTALL_DIR}/js/three.min.js" "${CMAKE_SOURCE_DIR}/newview/skins/default/html/common/equirectangular/js/three.min.js" COPYONLY)
# Controls to move around the scene using mouse or keyboard
#configure_file("${AUTOBUILD_INSTALL_DIR}/js/OrbitControls.js" "${CMAKE_SOURCE_DIR}/newview/skins/default/html/common/equirectangular/js/OrbitControls.js" COPYONLY)

View File

@ -60,7 +60,7 @@ if (EXISTS ${CMAKE_SOURCE_DIR}/Server.cmake)
set(INSTALL_PROPRIETARY ON CACHE BOOL "Install proprietary binaries")
endif (EXISTS ${CMAKE_SOURCE_DIR}/Server.cmake)
set(TEMPLATE_VERIFIER_OPTIONS "" CACHE STRING "Options for scripts/template_verifier.py")
set(TEMPLATE_VERIFIER_MASTER_URL "https://bitbucket.org/lindenlab/master-message-template-git/raw/HEAD/message_template.msg" CACHE STRING "Location of the master message template")
set(TEMPLATE_VERIFIER_MASTER_URL "https://bitbucket.org/lindenlab/master-message-template-git/raw/master/message_template.msg" CACHE STRING "Location of the master message template")
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING

View File

@ -1,3 +1,3 @@
euclid 5/29/2020
euclid 7/23/2020
euclid 4/29/2021
euclid 4/29/2021

View File

@ -70,7 +70,7 @@ BOOL LLViewerVisualParamInfo::parseXml(LLXmlTreeNode *node)
static LLStdStringHandle wearable_string = LLXmlTree::addAttributeString("wearable");
if( node->getFastAttributeString( wearable_string, wearable) )
{
mWearableType = LLWearableType::typeNameToType( wearable );
mWearableType = LLWearableType::getInstance()->typeNameToType( wearable );
}
static LLStdStringHandle edit_group_string = LLXmlTree::addAttributeString("edit_group");

View File

@ -76,17 +76,17 @@ LLWearable::~LLWearable()
const std::string& LLWearable::getTypeLabel() const
{
return LLWearableType::getTypeLabel(mType);
return LLWearableType::getInstance()->getTypeLabel(mType);
}
const std::string& LLWearable::getTypeName() const
{
return LLWearableType::getTypeName(mType);
return LLWearableType::getInstance()->getTypeName(mType);
}
LLAssetType::EType LLWearable::getAssetType() const
{
return LLWearableType::getAssetType(mType);
return LLWearableType::getInstance()->getAssetType(mType);
}
BOOL LLWearable::exportFile(const std::string& filename) const

View File

@ -241,10 +241,11 @@ BOOL LLWearableData::getWearableIndex(const LLWearable *wearable, U32& index_fou
U32 LLWearableData::getClothingLayerCount() const
{
U32 count = 0;
LLWearableType *wr_inst = LLWearableType::getInstance();
for (S32 i = 0; i < LLWearableType::WT_COUNT; i++)
{
LLWearableType::EType type = (LLWearableType::EType)i;
if (LLWearableType::getAssetType(type)==LLAssetType::AT_CLOTHING)
if (wr_inst->getAssetType(type)==LLAssetType::AT_CLOTHING)
{
count += getWearableCount(type);
}
@ -254,7 +255,7 @@ U32 LLWearableData::getClothingLayerCount() const
BOOL LLWearableData::canAddWearable(const LLWearableType::EType type) const
{
LLAssetType::EType a_type = LLWearableType::getAssetType(type);
LLAssetType::EType a_type = LLWearableType::getInstance()->getAssetType(type);
if (a_type==LLAssetType::AT_CLOTHING)
{
if (type == LLWearableType::WT_PHYSICS) return (getWearableCount(type) < 1); // <FS:Ansariel> Don't add physics layer

View File

@ -30,162 +30,101 @@
#include "llinventorydefines.h"
struct WearableEntry : public LLDictionaryEntry
LLWearableType::LLWearableDictionary::LLWearableDictionary(LLTranslationBridge::ptr_t& trans)
{
WearableEntry(LLWearableType& wtype,
const std::string &name,
const std::string& default_new_name,
LLAssetType::EType assetType,
LLInventoryType::EIconName iconName,
BOOL disable_camera_switch = FALSE,
BOOL allow_multiwear = TRUE) :
LLDictionaryEntry(name),
mAssetType(assetType),
mDefaultNewName(default_new_name),
mLabel(wtype.mTrans->getString(name)),
mIconName(iconName),
mDisableCameraSwitch(disable_camera_switch),
mAllowMultiwear(allow_multiwear)
{
}
const LLAssetType::EType mAssetType;
const std::string mLabel;
const std::string mDefaultNewName; //keep mLabel for backward compatibility
LLInventoryType::EIconName mIconName;
BOOL mDisableCameraSwitch;
BOOL mAllowMultiwear;
};
class LLWearableDictionary : public LLParamSingleton<LLWearableDictionary>,
public LLDictionary<LLWearableType::EType, WearableEntry>
{
LLSINGLETON(LLWearableDictionary, LLWearableType&);
// [RLVa:KB] - Checked: 2010-03-03 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
protected:
// The default implementation asserts on 'notFound()' and returns -1 which isn't a valid EWearableType
virtual LLWearableType::EType notFound() const { return LLWearableType::WT_INVALID; }
// [/RLVa:KB]
};
LLWearableDictionary::LLWearableDictionary(LLWearableType& wtype)
{
addEntry(LLWearableType::WT_SHAPE, new WearableEntry(wtype, "shape", "New Shape", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_SHAPE, FALSE, FALSE));
addEntry(LLWearableType::WT_SKIN, new WearableEntry(wtype, "skin", "New Skin", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_SKIN, FALSE, FALSE));
addEntry(LLWearableType::WT_HAIR, new WearableEntry(wtype, "hair", "New Hair", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_HAIR, FALSE, FALSE));
addEntry(LLWearableType::WT_EYES, new WearableEntry(wtype, "eyes", "New Eyes", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_EYES, FALSE, FALSE));
addEntry(LLWearableType::WT_SHIRT, new WearableEntry(wtype, "shirt", "New Shirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SHIRT, FALSE, TRUE));
addEntry(LLWearableType::WT_PANTS, new WearableEntry(wtype, "pants", "New Pants", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PANTS, FALSE, TRUE));
addEntry(LLWearableType::WT_SHOES, new WearableEntry(wtype, "shoes", "New Shoes", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SHOES, FALSE, TRUE));
addEntry(LLWearableType::WT_SOCKS, new WearableEntry(wtype, "socks", "New Socks", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SOCKS, FALSE, TRUE));
addEntry(LLWearableType::WT_JACKET, new WearableEntry(wtype, "jacket", "New Jacket", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_JACKET, FALSE, TRUE));
addEntry(LLWearableType::WT_GLOVES, new WearableEntry(wtype, "gloves", "New Gloves", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_GLOVES, FALSE, TRUE));
addEntry(LLWearableType::WT_UNDERSHIRT, new WearableEntry(wtype, "undershirt", "New Undershirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNDERSHIRT, FALSE, TRUE));
addEntry(LLWearableType::WT_UNDERPANTS, new WearableEntry(wtype, "underpants", "New Underpants", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNDERPANTS, FALSE, TRUE));
addEntry(LLWearableType::WT_SKIRT, new WearableEntry(wtype, "skirt", "New Skirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SKIRT, FALSE, TRUE));
addEntry(LLWearableType::WT_ALPHA, new WearableEntry(wtype, "alpha", "New Alpha", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_ALPHA, FALSE, TRUE));
addEntry(LLWearableType::WT_TATTOO, new WearableEntry(wtype, "tattoo", "New Tattoo", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_TATTOO, FALSE, TRUE));
addEntry(LLWearableType::WT_UNIVERSAL, new WearableEntry(wtype, "universal", "New Universal", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNIVERSAL, FALSE, TRUE));
addEntry(LLWearableType::WT_SHAPE, new WearableEntry(trans, "shape", "New Shape", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_SHAPE, FALSE, FALSE));
addEntry(LLWearableType::WT_SKIN, new WearableEntry(trans, "skin", "New Skin", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_SKIN, FALSE, FALSE));
addEntry(LLWearableType::WT_HAIR, new WearableEntry(trans, "hair", "New Hair", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_HAIR, FALSE, FALSE));
addEntry(LLWearableType::WT_EYES, new WearableEntry(trans, "eyes", "New Eyes", LLAssetType::AT_BODYPART, LLInventoryType::ICONNAME_BODYPART_EYES, FALSE, FALSE));
addEntry(LLWearableType::WT_SHIRT, new WearableEntry(trans, "shirt", "New Shirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SHIRT, FALSE, TRUE));
addEntry(LLWearableType::WT_PANTS, new WearableEntry(trans, "pants", "New Pants", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PANTS, FALSE, TRUE));
addEntry(LLWearableType::WT_SHOES, new WearableEntry(trans, "shoes", "New Shoes", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SHOES, FALSE, TRUE));
addEntry(LLWearableType::WT_SOCKS, new WearableEntry(trans, "socks", "New Socks", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SOCKS, FALSE, TRUE));
addEntry(LLWearableType::WT_JACKET, new WearableEntry(trans, "jacket", "New Jacket", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_JACKET, FALSE, TRUE));
addEntry(LLWearableType::WT_GLOVES, new WearableEntry(trans, "gloves", "New Gloves", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_GLOVES, FALSE, TRUE));
addEntry(LLWearableType::WT_UNDERSHIRT, new WearableEntry(trans, "undershirt", "New Undershirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNDERSHIRT, FALSE, TRUE));
addEntry(LLWearableType::WT_UNDERPANTS, new WearableEntry(trans, "underpants", "New Underpants", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNDERPANTS, FALSE, TRUE));
addEntry(LLWearableType::WT_SKIRT, new WearableEntry(trans, "skirt", "New Skirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SKIRT, FALSE, TRUE));
addEntry(LLWearableType::WT_ALPHA, new WearableEntry(trans, "alpha", "New Alpha", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_ALPHA, FALSE, TRUE));
addEntry(LLWearableType::WT_TATTOO, new WearableEntry(trans, "tattoo", "New Tattoo", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_TATTOO, FALSE, TRUE));
addEntry(LLWearableType::WT_UNIVERSAL, new WearableEntry(trans, "universal", "New Universal", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNIVERSAL, FALSE, TRUE));
// [SL:KB] - Patch: Appearance-Misc | Checked: 2011-05-29 (Catznip-2.6)
addEntry(LLWearableType::WT_PHYSICS, new WearableEntry(wtype, "physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PHYSICS, TRUE, FALSE));
addEntry(LLWearableType::WT_PHYSICS, new WearableEntry(trans, "physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PHYSICS, TRUE, FALSE));
// [/SL:KB]
// addEntry(LLWearableType::WT_PHYSICS, new WearableEntry(wtype, "physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PHYSICS, TRUE, TRUE));
// addEntry(LLWearableType::WT_PHYSICS, new WearableEntry(trans, "physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PHYSICS, TRUE, TRUE));
addEntry(LLWearableType::WT_INVALID, new WearableEntry(wtype, "invalid", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryType::ICONNAME_UNKNOWN, FALSE, FALSE));
addEntry(LLWearableType::WT_NONE, new WearableEntry(wtype, "none", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryType::ICONNAME_NONE, FALSE, FALSE));
addEntry(LLWearableType::WT_INVALID, new WearableEntry(trans, "invalid", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryType::ICONNAME_UNKNOWN, FALSE, FALSE));
addEntry(LLWearableType::WT_NONE, new WearableEntry(trans, "none", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryType::ICONNAME_NONE, FALSE, FALSE));
}
// class LLWearableType
LLWearableType::LLWearableType(LLTranslationBridge* trans)
LLWearableType::LLWearableType(LLTranslationBridge::ptr_t &trans)
: mDictionary(trans)
{
// LLTranslationBridge exists, but is not ready at this point in time since strings.xml is not yet loaded
mTrans = trans;
}
LLWearableType::~LLWearableType()
{
delete mTrans;
}
void LLWearableType::initSingleton()
{
// To make sure all wrapping functions will crash without initing LLWearableType;
LLWearableDictionary::initParamSingleton(*this);
// Todo: consider merging LLWearableType and LLWearableDictionary
}
// static
LLWearableType::EType LLWearableType::typeNameToType(const std::string& type_name)
{
const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
const LLWearableType::EType wearable = dict->lookup(type_name);
const LLWearableType::EType wearable = mDictionary.lookup(type_name);
return wearable;
}
// static
const std::string& LLWearableType::getTypeName(LLWearableType::EType type)
{
const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
const WearableEntry *entry = dict->lookup(type);
const WearableEntry *entry = mDictionary.lookup(type);
if (!entry) return getTypeName(WT_INVALID);
return entry->mName;
}
//static
const std::string& LLWearableType::getTypeDefaultNewName(LLWearableType::EType type)
{
const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
const WearableEntry *entry = dict->lookup(type);
const WearableEntry *entry = mDictionary.lookup(type);
if (!entry) return getTypeDefaultNewName(WT_INVALID);
return entry->mDefaultNewName;
}
// static
const std::string& LLWearableType::getTypeLabel(LLWearableType::EType type)
{
const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
const WearableEntry *entry = dict->lookup(type);
const WearableEntry *entry = mDictionary.lookup(type);
if (!entry) return getTypeLabel(WT_INVALID);
return entry->mLabel;
}
// static
LLAssetType::EType LLWearableType::getAssetType(LLWearableType::EType type)
{
const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
const WearableEntry *entry = dict->lookup(type);
const WearableEntry *entry = mDictionary.lookup(type);
if (!entry) return getAssetType(WT_INVALID);
return entry->mAssetType;
}
// static
LLInventoryType::EIconName LLWearableType::getIconName(LLWearableType::EType type)
{
const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
const WearableEntry *entry = dict->lookup(type);
const WearableEntry *entry = mDictionary.lookup(type);
if (!entry) return getIconName(WT_INVALID);
return entry->mIconName;
}
// static
BOOL LLWearableType::getDisableCameraSwitch(LLWearableType::EType type)
{
const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
const WearableEntry *entry = dict->lookup(type);
const WearableEntry *entry = mDictionary.lookup(type);
if (!entry) return FALSE;
return entry->mDisableCameraSwitch;
}
// static
BOOL LLWearableType::getAllowMultiwear(LLWearableType::EType type)
{
const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
const WearableEntry *entry = dict->lookup(type);
const WearableEntry *entry = mDictionary.lookup(type);
if (!entry) return FALSE;
return entry->mAllowMultiwear;
}

View File

@ -35,10 +35,9 @@
class LLWearableType : public LLParamSingleton<LLWearableType>
{
LLSINGLETON(LLWearableType, LLTranslationBridge* trans);
LLSINGLETON(LLWearableType, LLTranslationBridge::ptr_t &trans);
~LLWearableType();
void initSingleton();
friend struct WearableEntry;
public:
enum EType
{
@ -67,20 +66,59 @@ public:
// Most methods are wrappers for dictionary, but if LLWearableType is not initialized,
// they will crash. Whole LLWearableType is just wrapper for convinient calls.
static const std::string& getTypeName(EType type);
static const std::string& getTypeDefaultNewName(EType type);
static const std::string& getTypeLabel(EType type);
static LLAssetType::EType getAssetType(EType type);
static EType typeNameToType(const std::string& type_name);
static LLInventoryType::EIconName getIconName(EType type);
static BOOL getDisableCameraSwitch(EType type);
static BOOL getAllowMultiwear(EType type);
const std::string& getTypeName(EType type);
const std::string& getTypeDefaultNewName(EType type);
const std::string& getTypeLabel(EType type);
LLAssetType::EType getAssetType(EType type);
EType typeNameToType(const std::string& type_name);
LLInventoryType::EIconName getIconName(EType type);
BOOL getDisableCameraSwitch(EType type);
BOOL getAllowMultiwear(EType type);
static EType inventoryFlagsToWearableType(U32 flags);
protected:
private:
struct WearableEntry : public LLDictionaryEntry
{
WearableEntry(LLTranslationBridge::ptr_t& trans,
const std::string &name,
const std::string& default_new_name,
LLAssetType::EType assetType,
LLInventoryType::EIconName iconName,
BOOL disable_camera_switch = FALSE,
BOOL allow_multiwear = TRUE) :
LLDictionaryEntry(name),
mAssetType(assetType),
mDefaultNewName(default_new_name),
mLabel(trans->getString(name)),
mIconName(iconName),
mDisableCameraSwitch(disable_camera_switch),
mAllowMultiwear(allow_multiwear)
{
LLTranslationBridge* mTrans;
}
const LLAssetType::EType mAssetType;
const std::string mLabel;
const std::string mDefaultNewName;
LLInventoryType::EIconName mIconName;
BOOL mDisableCameraSwitch;
BOOL mAllowMultiwear;
};
class LLWearableDictionary : public LLDictionary<LLWearableType::EType, WearableEntry>
{
public:
LLWearableDictionary(LLTranslationBridge::ptr_t& trans);
~LLWearableDictionary() {}
// [RLVa:KB] - Checked: 2010-03-03 (RLVa-1.2.0a) | Added: RLVa-1.2.0a
protected:
// The default implementation asserts on 'notFound()' and returns -1 which isn't a valid EWearableType
virtual LLWearableType::EType notFound() const { return LLWearableType::WT_INVALID; }
// [/RLVa:KB]
};
LLWearableDictionary mDictionary;
};
#endif // LL_LLWEARABLETYPE_H

View File

@ -72,7 +72,8 @@ mSystem(system),
mCurrentInternetStreamp(NULL),
mStreamGroup(NULL),
mFMODInternetStreamChannelp(NULL),
mGain(1.0f)
mGain(1.0f),
mWasAlreadyPlaying(false)
{
// Number of milliseconds of audio to buffer for the audio card.
// Must be larger than the usual Second Life frame stutter time.
@ -158,18 +159,14 @@ void LLStreamingAudio_FMODSTUDIO::update()
if (Check_FMOD_Error(mCurrentInternetStreamp->getOpenState(open_state, &progress, &starving, &diskbusy), "FMOD::Sound::getOpenState"))
{
LL_WARNS() << "Internet stream openstate error: open_state = " << open_state << " - progress = " << progress << " - starving = " << starving << " - diskbusy = " << diskbusy << LL_ENDL;
bool was_playing = mWasAlreadyPlaying;
stop();
return;
}
else if (open_state == FMOD_OPENSTATE_ERROR)
{
// Actually we might not get into this case at all since according to the
// FMOD API doc, one should check the result of getOpenState for further
// details, which most likely means if open_state is FMOD_OPENSTATE_ERROR,
// calling getOpenState will return anything but FMOD_OK and we end up in
// the if-case above.
LL_WARNS() << "Internet stream openstate error: progress = " << progress << " - starving = " << starving << " - diskbusy = " << diskbusy << LL_ENDL;
stop();
// Try to restart previously playing stream on socket error
if (open_state == FMOD_OPENSTATE_ERROR && was_playing)
{
LL_WARNS() << "Stream was playing before - trying to restart" << LL_ENDL;
start(mURL);
}
return;
}
else if (open_state == FMOD_OPENSTATE_READY)
@ -183,6 +180,14 @@ void LLStreamingAudio_FMODSTUDIO::update()
// Reset volume to previously set volume
setGain(getGain());
Check_FMOD_Error(mFMODInternetStreamChannelp->setPaused(false), "FMOD::Channel::setPaused");
mWasAlreadyPlaying = true;
}
}
else if (open_state == FMOD_OPENSTATE_PLAYING)
{
if (!mWasAlreadyPlaying)
{
mWasAlreadyPlaying = true;
}
}
@ -317,6 +322,7 @@ void LLStreamingAudio_FMODSTUDIO::update()
void LLStreamingAudio_FMODSTUDIO::stop()
{
mPendingURL.clear();
mWasAlreadyPlaying = false;
if (mFMODInternetStreamChannelp)
{

View File

@ -80,6 +80,8 @@ private:
bool mNewMetadata;
LLSD mMetadata;
// </DKO> Streamtitle display
bool mWasAlreadyPlaying;
};

View File

@ -9,7 +9,6 @@ include(Linking)
include(Boost)
include(LLSharedLibs)
include(JsonCpp)
include(GoogleBreakpad)
include(Copy3rdPartyLibs)
include(ZLIB)
include(URIPARSER)
@ -19,7 +18,6 @@ include_directories(
${LLCOMMON_INCLUDE_DIRS}
${JSONCPP_INCLUDE_DIR}
${ZLIB_INCLUDE_DIRS}
${BREAKPAD_INCLUDE_DIRECTORIES}
${URIPARSER_INCLUDE_DIRS}
)
@ -210,9 +208,9 @@ set(llcommon_HEADER_FILES
llqueuedthread.h
llrand.h
llrefcount.h
llregex.h
llregistry.h
llrun.h
llrefcount.h
llsafehandle.h
llsd.h
llsdjson.h
@ -258,13 +256,14 @@ set(llcommon_HEADER_FILES
StackWalker.h
)
# <FS:ND> Add all nd* files. memory pool, intrinsics, ...
# <FS:Beq> Tracy Profiler support
list(APPEND llcommon_SOURCE_FILES fstelemetry.cpp)
if (USE_TRACY_PROFILER)
list(APPEND llcommon_SOURCE_FILES fstracyclient.cpp)
endif()
# <FS:Beq> Tracy Profiler support
list(APPEND llcommon_SOURCE_FILES fstelemetry.cpp)
if (USE_TRACY_PROFILER)
list(APPEND llcommon_SOURCE_FILES fstracyclient.cpp)
endif()
# </FS:Beq> Tracy Profiler support
# <FS:ND> Add all nd* files. memory pool, intrinsics, ...
SET( llcommon_ND_SOURCE_FILES
nd/ndexceptions.cpp
nd/ndlogthrottle.cpp
@ -329,7 +328,6 @@ endif(NOT WORD_SIZE EQUAL 32)
target_link_libraries(
llcommon
${BREAKPAD_EXCEPTION_HANDLER_LIBRARIES}
${APRUTIL_LIBRARIES}
${APR_LIBRARIES}
${EXPAT_LIBRARIES}

View File

@ -0,0 +1,582 @@
// Provides an efficient blocking version of moodycamel::ConcurrentQueue.
// ©2015-2020 Cameron Desrochers. Distributed under the terms of the simplified
// BSD license, available at the top of concurrentqueue.h.
// Also dual-licensed under the Boost Software License (see LICENSE.md)
// Uses Jeff Preshing's semaphore implementation (under the terms of its
// separate zlib license, see lightweightsemaphore.h).
#pragma once
#include "concurrentqueue.h"
#include "lightweightsemaphore.h"
#include <type_traits>
#include <cerrno>
#include <memory>
#include <chrono>
#include <ctime>
namespace moodycamel
{
// This is a blocking version of the queue. It has an almost identical interface to
// the normal non-blocking version, with the addition of various wait_dequeue() methods
// and the removal of producer-specific dequeue methods.
template<typename T, typename Traits = ConcurrentQueueDefaultTraits>
class BlockingConcurrentQueue
{
private:
typedef ::moodycamel::ConcurrentQueue<T, Traits> ConcurrentQueue;
typedef ::moodycamel::LightweightSemaphore LightweightSemaphore;
public:
typedef typename ConcurrentQueue::producer_token_t producer_token_t;
typedef typename ConcurrentQueue::consumer_token_t consumer_token_t;
typedef typename ConcurrentQueue::index_t index_t;
typedef typename ConcurrentQueue::size_t size_t;
typedef typename std::make_signed<size_t>::type ssize_t;
static const size_t BLOCK_SIZE = ConcurrentQueue::BLOCK_SIZE;
static const size_t EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD = ConcurrentQueue::EXPLICIT_BLOCK_EMPTY_COUNTER_THRESHOLD;
static const size_t EXPLICIT_INITIAL_INDEX_SIZE = ConcurrentQueue::EXPLICIT_INITIAL_INDEX_SIZE;
static const size_t IMPLICIT_INITIAL_INDEX_SIZE = ConcurrentQueue::IMPLICIT_INITIAL_INDEX_SIZE;
static const size_t INITIAL_IMPLICIT_PRODUCER_HASH_SIZE = ConcurrentQueue::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE;
static const std::uint32_t EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE = ConcurrentQueue::EXPLICIT_CONSUMER_CONSUMPTION_QUOTA_BEFORE_ROTATE;
static const size_t MAX_SUBQUEUE_SIZE = ConcurrentQueue::MAX_SUBQUEUE_SIZE;
public:
// Creates a queue with at least `capacity` element slots; note that the
// actual number of elements that can be inserted without additional memory
// allocation depends on the number of producers and the block size (e.g. if
// the block size is equal to `capacity`, only a single block will be allocated
// up-front, which means only a single producer will be able to enqueue elements
// without an extra allocation -- blocks aren't shared between producers).
// This method is not thread safe -- it is up to the user to ensure that the
// queue is fully constructed before it starts being used by other threads (this
// includes making the memory effects of construction visible, possibly with a
// memory barrier).
explicit BlockingConcurrentQueue(size_t capacity = 6 * BLOCK_SIZE)
: inner(capacity), sema(create<LightweightSemaphore, ssize_t, int>(0, (int)Traits::MAX_SEMA_SPINS), &BlockingConcurrentQueue::template destroy<LightweightSemaphore>)
{
assert(reinterpret_cast<ConcurrentQueue*>((BlockingConcurrentQueue*)1) == &((BlockingConcurrentQueue*)1)->inner && "BlockingConcurrentQueue must have ConcurrentQueue as its first member");
if (!sema) {
MOODYCAMEL_THROW(std::bad_alloc());
}
}
BlockingConcurrentQueue(size_t minCapacity, size_t maxExplicitProducers, size_t maxImplicitProducers)
: inner(minCapacity, maxExplicitProducers, maxImplicitProducers), sema(create<LightweightSemaphore, ssize_t, int>(0, (int)Traits::MAX_SEMA_SPINS), &BlockingConcurrentQueue::template destroy<LightweightSemaphore>)
{
assert(reinterpret_cast<ConcurrentQueue*>((BlockingConcurrentQueue*)1) == &((BlockingConcurrentQueue*)1)->inner && "BlockingConcurrentQueue must have ConcurrentQueue as its first member");
if (!sema) {
MOODYCAMEL_THROW(std::bad_alloc());
}
}
// Disable copying and copy assignment
BlockingConcurrentQueue(BlockingConcurrentQueue const&) MOODYCAMEL_DELETE_FUNCTION;
BlockingConcurrentQueue& operator=(BlockingConcurrentQueue const&) MOODYCAMEL_DELETE_FUNCTION;
// Moving is supported, but note that it is *not* a thread-safe operation.
// Nobody can use the queue while it's being moved, and the memory effects
// of that move must be propagated to other threads before they can use it.
// Note: When a queue is moved, its tokens are still valid but can only be
// used with the destination queue (i.e. semantically they are moved along
// with the queue itself).
BlockingConcurrentQueue(BlockingConcurrentQueue&& other) MOODYCAMEL_NOEXCEPT
: inner(std::move(other.inner)), sema(std::move(other.sema))
{ }
inline BlockingConcurrentQueue& operator=(BlockingConcurrentQueue&& other) MOODYCAMEL_NOEXCEPT
{
return swap_internal(other);
}
// Swaps this queue's state with the other's. Not thread-safe.
// Swapping two queues does not invalidate their tokens, however
// the tokens that were created for one queue must be used with
// only the swapped queue (i.e. the tokens are tied to the
// queue's movable state, not the object itself).
inline void swap(BlockingConcurrentQueue& other) MOODYCAMEL_NOEXCEPT
{
swap_internal(other);
}
private:
BlockingConcurrentQueue& swap_internal(BlockingConcurrentQueue& other)
{
if (this == &other) {
return *this;
}
inner.swap(other.inner);
sema.swap(other.sema);
return *this;
}
public:
// Enqueues a single item (by copying it).
// Allocates memory if required. Only fails if memory allocation fails (or implicit
// production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0,
// or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed).
// Thread-safe.
inline bool enqueue(T const& item)
{
if ((details::likely)(inner.enqueue(item))) {
sema->signal();
return true;
}
return false;
}
// Enqueues a single item (by moving it, if possible).
// Allocates memory if required. Only fails if memory allocation fails (or implicit
// production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0,
// or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed).
// Thread-safe.
inline bool enqueue(T&& item)
{
if ((details::likely)(inner.enqueue(std::move(item)))) {
sema->signal();
return true;
}
return false;
}
// Enqueues a single item (by copying it) using an explicit producer token.
// Allocates memory if required. Only fails if memory allocation fails (or
// Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed).
// Thread-safe.
inline bool enqueue(producer_token_t const& token, T const& item)
{
if ((details::likely)(inner.enqueue(token, item))) {
sema->signal();
return true;
}
return false;
}
// Enqueues a single item (by moving it, if possible) using an explicit producer token.
// Allocates memory if required. Only fails if memory allocation fails (or
// Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed).
// Thread-safe.
inline bool enqueue(producer_token_t const& token, T&& item)
{
if ((details::likely)(inner.enqueue(token, std::move(item)))) {
sema->signal();
return true;
}
return false;
}
// Enqueues several items.
// Allocates memory if required. Only fails if memory allocation fails (or
// implicit production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE
// is 0, or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed).
// Note: Use std::make_move_iterator if the elements should be moved instead of copied.
// Thread-safe.
template<typename It>
inline bool enqueue_bulk(It itemFirst, size_t count)
{
if ((details::likely)(inner.enqueue_bulk(std::forward<It>(itemFirst), count))) {
sema->signal((LightweightSemaphore::ssize_t)(ssize_t)count);
return true;
}
return false;
}
// Enqueues several items using an explicit producer token.
// Allocates memory if required. Only fails if memory allocation fails
// (or Traits::MAX_SUBQUEUE_SIZE has been defined and would be surpassed).
// Note: Use std::make_move_iterator if the elements should be moved
// instead of copied.
// Thread-safe.
template<typename It>
inline bool enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count)
{
if ((details::likely)(inner.enqueue_bulk(token, std::forward<It>(itemFirst), count))) {
sema->signal((LightweightSemaphore::ssize_t)(ssize_t)count);
return true;
}
return false;
}
// Enqueues a single item (by copying it).
// Does not allocate memory. Fails if not enough room to enqueue (or implicit
// production is disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE
// is 0).
// Thread-safe.
inline bool try_enqueue(T const& item)
{
if (inner.try_enqueue(item)) {
sema->signal();
return true;
}
return false;
}
// Enqueues a single item (by moving it, if possible).
// Does not allocate memory (except for one-time implicit producer).
// Fails if not enough room to enqueue (or implicit production is
// disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0).
// Thread-safe.
inline bool try_enqueue(T&& item)
{
if (inner.try_enqueue(std::move(item))) {
sema->signal();
return true;
}
return false;
}
// Enqueues a single item (by copying it) using an explicit producer token.
// Does not allocate memory. Fails if not enough room to enqueue.
// Thread-safe.
inline bool try_enqueue(producer_token_t const& token, T const& item)
{
if (inner.try_enqueue(token, item)) {
sema->signal();
return true;
}
return false;
}
// Enqueues a single item (by moving it, if possible) using an explicit producer token.
// Does not allocate memory. Fails if not enough room to enqueue.
// Thread-safe.
inline bool try_enqueue(producer_token_t const& token, T&& item)
{
if (inner.try_enqueue(token, std::move(item))) {
sema->signal();
return true;
}
return false;
}
// Enqueues several items.
// Does not allocate memory (except for one-time implicit producer).
// Fails if not enough room to enqueue (or implicit production is
// disabled because Traits::INITIAL_IMPLICIT_PRODUCER_HASH_SIZE is 0).
// Note: Use std::make_move_iterator if the elements should be moved
// instead of copied.
// Thread-safe.
template<typename It>
inline bool try_enqueue_bulk(It itemFirst, size_t count)
{
if (inner.try_enqueue_bulk(std::forward<It>(itemFirst), count)) {
sema->signal((LightweightSemaphore::ssize_t)(ssize_t)count);
return true;
}
return false;
}
// Enqueues several items using an explicit producer token.
// Does not allocate memory. Fails if not enough room to enqueue.
// Note: Use std::make_move_iterator if the elements should be moved
// instead of copied.
// Thread-safe.
template<typename It>
inline bool try_enqueue_bulk(producer_token_t const& token, It itemFirst, size_t count)
{
if (inner.try_enqueue_bulk(token, std::forward<It>(itemFirst), count)) {
sema->signal((LightweightSemaphore::ssize_t)(ssize_t)count);
return true;
}
return false;
}
// Attempts to dequeue from the queue.
// Returns false if all producer streams appeared empty at the time they
// were checked (so, the queue is likely but not guaranteed to be empty).
// Never allocates. Thread-safe.
template<typename U>
inline bool try_dequeue(U& item)
{
if (sema->tryWait()) {
while (!inner.try_dequeue(item)) {
continue;
}
return true;
}
return false;
}
// Attempts to dequeue from the queue using an explicit consumer token.
// Returns false if all producer streams appeared empty at the time they
// were checked (so, the queue is likely but not guaranteed to be empty).
// Never allocates. Thread-safe.
template<typename U>
inline bool try_dequeue(consumer_token_t& token, U& item)
{
if (sema->tryWait()) {
while (!inner.try_dequeue(token, item)) {
continue;
}
return true;
}
return false;
}
// Attempts to dequeue several elements from the queue.
// Returns the number of items actually dequeued.
// Returns 0 if all producer streams appeared empty at the time they
// were checked (so, the queue is likely but not guaranteed to be empty).
// Never allocates. Thread-safe.
template<typename It>
inline size_t try_dequeue_bulk(It itemFirst, size_t max)
{
size_t count = 0;
max = (size_t)sema->tryWaitMany((LightweightSemaphore::ssize_t)(ssize_t)max);
while (count != max) {
count += inner.template try_dequeue_bulk<It&>(itemFirst, max - count);
}
return count;
}
// Attempts to dequeue several elements from the queue using an explicit consumer token.
// Returns the number of items actually dequeued.
// Returns 0 if all producer streams appeared empty at the time they
// were checked (so, the queue is likely but not guaranteed to be empty).
// Never allocates. Thread-safe.
template<typename It>
inline size_t try_dequeue_bulk(consumer_token_t& token, It itemFirst, size_t max)
{
size_t count = 0;
max = (size_t)sema->tryWaitMany((LightweightSemaphore::ssize_t)(ssize_t)max);
while (count != max) {
count += inner.template try_dequeue_bulk<It&>(token, itemFirst, max - count);
}
return count;
}
// Blocks the current thread until there's something to dequeue, then
// dequeues it.
// Never allocates. Thread-safe.
template<typename U>
inline void wait_dequeue(U& item)
{
while (!sema->wait()) {
continue;
}
while (!inner.try_dequeue(item)) {
continue;
}
}
// Blocks the current thread until either there's something to dequeue
// or the timeout (specified in microseconds) expires. Returns false
// without setting `item` if the timeout expires, otherwise assigns
// to `item` and returns true.
// Using a negative timeout indicates an indefinite timeout,
// and is thus functionally equivalent to calling wait_dequeue.
// Never allocates. Thread-safe.
template<typename U>
inline bool wait_dequeue_timed(U& item, std::int64_t timeout_usecs)
{
if (!sema->wait(timeout_usecs)) {
return false;
}
while (!inner.try_dequeue(item)) {
continue;
}
return true;
}
// Blocks the current thread until either there's something to dequeue
// or the timeout expires. Returns false without setting `item` if the
// timeout expires, otherwise assigns to `item` and returns true.
// Never allocates. Thread-safe.
template<typename U, typename Rep, typename Period>
inline bool wait_dequeue_timed(U& item, std::chrono::duration<Rep, Period> const& timeout)
{
return wait_dequeue_timed(item, std::chrono::duration_cast<std::chrono::microseconds>(timeout).count());
}
// Blocks the current thread until there's something to dequeue, then
// dequeues it using an explicit consumer token.
// Never allocates. Thread-safe.
template<typename U>
inline void wait_dequeue(consumer_token_t& token, U& item)
{
while (!sema->wait()) {
continue;
}
while (!inner.try_dequeue(token, item)) {
continue;
}
}
// Blocks the current thread until either there's something to dequeue
// or the timeout (specified in microseconds) expires. Returns false
// without setting `item` if the timeout expires, otherwise assigns
// to `item` and returns true.
// Using a negative timeout indicates an indefinite timeout,
// and is thus functionally equivalent to calling wait_dequeue.
// Never allocates. Thread-safe.
template<typename U>
inline bool wait_dequeue_timed(consumer_token_t& token, U& item, std::int64_t timeout_usecs)
{
if (!sema->wait(timeout_usecs)) {
return false;
}
while (!inner.try_dequeue(token, item)) {
continue;
}
return true;
}
// Blocks the current thread until either there's something to dequeue
// or the timeout expires. Returns false without setting `item` if the
// timeout expires, otherwise assigns to `item` and returns true.
// Never allocates. Thread-safe.
template<typename U, typename Rep, typename Period>
inline bool wait_dequeue_timed(consumer_token_t& token, U& item, std::chrono::duration<Rep, Period> const& timeout)
{
return wait_dequeue_timed(token, item, std::chrono::duration_cast<std::chrono::microseconds>(timeout).count());
}
// Attempts to dequeue several elements from the queue.
// Returns the number of items actually dequeued, which will
// always be at least one (this method blocks until the queue
// is non-empty) and at most max.
// Never allocates. Thread-safe.
template<typename It>
inline size_t wait_dequeue_bulk(It itemFirst, size_t max)
{
size_t count = 0;
max = (size_t)sema->waitMany((LightweightSemaphore::ssize_t)(ssize_t)max);
while (count != max) {
count += inner.template try_dequeue_bulk<It&>(itemFirst, max - count);
}
return count;
}
// Attempts to dequeue several elements from the queue.
// Returns the number of items actually dequeued, which can
// be 0 if the timeout expires while waiting for elements,
// and at most max.
// Using a negative timeout indicates an indefinite timeout,
// and is thus functionally equivalent to calling wait_dequeue_bulk.
// Never allocates. Thread-safe.
template<typename It>
inline size_t wait_dequeue_bulk_timed(It itemFirst, size_t max, std::int64_t timeout_usecs)
{
size_t count = 0;
max = (size_t)sema->waitMany((LightweightSemaphore::ssize_t)(ssize_t)max, timeout_usecs);
while (count != max) {
count += inner.template try_dequeue_bulk<It&>(itemFirst, max - count);
}
return count;
}
// Attempts to dequeue several elements from the queue.
// Returns the number of items actually dequeued, which can
// be 0 if the timeout expires while waiting for elements,
// and at most max.
// Never allocates. Thread-safe.
template<typename It, typename Rep, typename Period>
inline size_t wait_dequeue_bulk_timed(It itemFirst, size_t max, std::chrono::duration<Rep, Period> const& timeout)
{
return wait_dequeue_bulk_timed<It&>(itemFirst, max, std::chrono::duration_cast<std::chrono::microseconds>(timeout).count());
}
// Attempts to dequeue several elements from the queue using an explicit consumer token.
// Returns the number of items actually dequeued, which will
// always be at least one (this method blocks until the queue
// is non-empty) and at most max.
// Never allocates. Thread-safe.
template<typename It>
inline size_t wait_dequeue_bulk(consumer_token_t& token, It itemFirst, size_t max)
{
size_t count = 0;
max = (size_t)sema->waitMany((LightweightSemaphore::ssize_t)(ssize_t)max);
while (count != max) {
count += inner.template try_dequeue_bulk<It&>(token, itemFirst, max - count);
}
return count;
}
// Attempts to dequeue several elements from the queue using an explicit consumer token.
// Returns the number of items actually dequeued, which can
// be 0 if the timeout expires while waiting for elements,
// and at most max.
// Using a negative timeout indicates an indefinite timeout,
// and is thus functionally equivalent to calling wait_dequeue_bulk.
// Never allocates. Thread-safe.
template<typename It>
inline size_t wait_dequeue_bulk_timed(consumer_token_t& token, It itemFirst, size_t max, std::int64_t timeout_usecs)
{
size_t count = 0;
max = (size_t)sema->waitMany((LightweightSemaphore::ssize_t)(ssize_t)max, timeout_usecs);
while (count != max) {
count += inner.template try_dequeue_bulk<It&>(token, itemFirst, max - count);
}
return count;
}
// Attempts to dequeue several elements from the queue using an explicit consumer token.
// Returns the number of items actually dequeued, which can
// be 0 if the timeout expires while waiting for elements,
// and at most max.
// Never allocates. Thread-safe.
template<typename It, typename Rep, typename Period>
inline size_t wait_dequeue_bulk_timed(consumer_token_t& token, It itemFirst, size_t max, std::chrono::duration<Rep, Period> const& timeout)
{
return wait_dequeue_bulk_timed<It&>(token, itemFirst, max, std::chrono::duration_cast<std::chrono::microseconds>(timeout).count());
}
// Returns an estimate of the total number of elements currently in the queue. This
// estimate is only accurate if the queue has completely stabilized before it is called
// (i.e. all enqueue and dequeue operations have completed and their memory effects are
// visible on the calling thread, and no further operations start while this method is
// being called).
// Thread-safe.
inline size_t size_approx() const
{
return (size_t)sema->availableApprox();
}
// Returns true if the underlying atomic variables used by
// the queue are lock-free (they should be on most platforms).
// Thread-safe.
static bool is_lock_free()
{
return ConcurrentQueue::is_lock_free();
}
private:
template<typename U, typename A1, typename A2>
static inline U* create(A1&& a1, A2&& a2)
{
void* p = (Traits::malloc)(sizeof(U));
return p != nullptr ? new (p) U(std::forward<A1>(a1), std::forward<A2>(a2)) : nullptr;
}
template<typename U>
static inline void destroy(U* p)
{
if (p != nullptr) {
p->~U();
}
(Traits::free)(p);
}
private:
ConcurrentQueue inner;
std::unique_ptr<LightweightSemaphore, void (*)(LightweightSemaphore*)> sema;
};
template<typename T, typename Traits>
inline void swap(BlockingConcurrentQueue<T, Traits>& a, BlockingConcurrentQueue<T, Traits>& b) MOODYCAMEL_NOEXCEPT
{
a.swap(b);
}
} // end namespace moodycamel

File diff suppressed because it is too large Load Diff

View File

@ -28,4 +28,5 @@
namespace FSTelemetry
{
bool active{false};
}

View File

@ -43,9 +43,15 @@
#define FSZoneN( name ) ZoneNamedN( ___tracy_scoped_zone, name, FSTelemetry::active)
#define FSZoneC( color ) ZoneNamedC( ___tracy_scoped_zone, color, FSTelemetry::active)
#define FSZoneNC( name, color ) ZoneNamedNC( ___tracy_scoped_zone, name, color, FSTelemetry::active)
#define FSZoneText( text, size ) ZoneText( text, size )
#define FSZoneValue( num_uint64 ) ZoneValue( num_uint64 )
#define FSPlot( name, value ) TracyPlot( name, value)
#define FSPlotSq( name, lastval, newval ) TracyPlot( name, lastval);TracyPlot( name, newval);
#define FSFrameMark FrameMark
#define FSFrameMarkStart( name ) FrameMarkStart( name )
#define FSFrameMarkEnd( name ) FrameMarkEnd( name )
#define FSThreadName( name ) tracy::SetThreadName( name )
#define FSMessageL ( message ) tracy::Profiler::Message( message, 0 )
#define FSTelemetryIsConnected TracyIsConnected
#else // (no telemetry)
@ -57,15 +63,26 @@
#define FSZoneN( name )
#define FSZoneC( color )
#define FSZoneNC( name, color )
#define FSZoneText( text, size )
#define FSZoneValue( num_uint64 )
#define FSPlot( name, value )
#define FSPlotSq( name, lastval, newval )
#define FSFrameMark
#define FSFrameMarkStart( name )
#define FSFrameMarkEnd( name )
#define FSThreadName( name )
#define FSMessageL( message )
#define FSTelemetryIsConnected
#endif // TRACY_ENABLE
#include <chrono>
#include <array>
#include <unordered_map>
namespace FSTelemetry
{
extern bool active;
}
}// namespace FSTelemetry
#endif

View File

@ -0,0 +1,411 @@
// Provides an efficient implementation of a semaphore (LightweightSemaphore).
// This is an extension of Jeff Preshing's sempahore implementation (licensed
// under the terms of its separate zlib license) that has been adapted and
// extended by Cameron Desrochers.
#pragma once
#include <cstddef> // For std::size_t
#include <atomic>
#include <type_traits> // For std::make_signed<T>
#if defined(_WIN32)
// Avoid including windows.h in a header; we only need a handful of
// items, so we'll redeclare them here (this is relatively safe since
// the API generally has to remain stable between Windows versions).
// I know this is an ugly hack but it still beats polluting the global
// namespace with thousands of generic names or adding a .cpp for nothing.
extern "C" {
struct _SECURITY_ATTRIBUTES;
__declspec(dllimport) void* __stdcall CreateSemaphoreW(_SECURITY_ATTRIBUTES* lpSemaphoreAttributes, long lInitialCount, long lMaximumCount, const wchar_t* lpName);
__declspec(dllimport) int __stdcall CloseHandle(void* hObject);
__declspec(dllimport) unsigned long __stdcall WaitForSingleObject(void* hHandle, unsigned long dwMilliseconds);
__declspec(dllimport) int __stdcall ReleaseSemaphore(void* hSemaphore, long lReleaseCount, long* lpPreviousCount);
}
#elif defined(__MACH__)
#include <mach/mach.h>
#elif defined(__unix__)
#include <semaphore.h>
#endif
namespace moodycamel
{
namespace details
{
// Code in the mpmc_sema namespace below is an adaptation of Jeff Preshing's
// portable + lightweight semaphore implementations, originally from
// https://github.com/preshing/cpp11-on-multicore/blob/master/common/sema.h
// LICENSE:
// Copyright (c) 2015 Jeff Preshing
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgement in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
#if defined(_WIN32)
class Semaphore
{
private:
void* m_hSema;
Semaphore(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION;
Semaphore& operator=(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION;
public:
Semaphore(int initialCount = 0)
{
assert(initialCount >= 0);
const long maxLong = 0x7fffffff;
m_hSema = CreateSemaphoreW(nullptr, initialCount, maxLong, nullptr);
assert(m_hSema);
}
~Semaphore()
{
CloseHandle(m_hSema);
}
bool wait()
{
const unsigned long infinite = 0xffffffff;
return WaitForSingleObject(m_hSema, infinite) == 0;
}
bool try_wait()
{
return WaitForSingleObject(m_hSema, 0) == 0;
}
bool timed_wait(std::uint64_t usecs)
{
return WaitForSingleObject(m_hSema, (unsigned long)(usecs / 1000)) == 0;
}
void signal(int count = 1)
{
while (!ReleaseSemaphore(m_hSema, count, nullptr));
}
};
#elif defined(__MACH__)
//---------------------------------------------------------
// Semaphore (Apple iOS and OSX)
// Can't use POSIX semaphores due to http://lists.apple.com/archives/darwin-kernel/2009/Apr/msg00010.html
//---------------------------------------------------------
class Semaphore
{
private:
semaphore_t m_sema;
Semaphore(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION;
Semaphore& operator=(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION;
public:
Semaphore(int initialCount = 0)
{
assert(initialCount >= 0);
kern_return_t rc = semaphore_create(mach_task_self(), &m_sema, SYNC_POLICY_FIFO, initialCount);
assert(rc == KERN_SUCCESS);
(void)rc;
}
~Semaphore()
{
semaphore_destroy(mach_task_self(), m_sema);
}
bool wait()
{
return semaphore_wait(m_sema) == KERN_SUCCESS;
}
bool try_wait()
{
return timed_wait(0);
}
bool timed_wait(std::uint64_t timeout_usecs)
{
mach_timespec_t ts;
ts.tv_sec = static_cast<unsigned int>(timeout_usecs / 1000000);
ts.tv_nsec = static_cast<int>((timeout_usecs % 1000000) * 1000);
// added in OSX 10.10: https://developer.apple.com/library/prerelease/mac/documentation/General/Reference/APIDiffsMacOSX10_10SeedDiff/modules/Darwin.html
kern_return_t rc = semaphore_timedwait(m_sema, ts);
return rc == KERN_SUCCESS;
}
void signal()
{
while (semaphore_signal(m_sema) != KERN_SUCCESS);
}
void signal(int count)
{
while (count-- > 0)
{
while (semaphore_signal(m_sema) != KERN_SUCCESS);
}
}
};
#elif defined(__unix__)
//---------------------------------------------------------
// Semaphore (POSIX, Linux)
//---------------------------------------------------------
class Semaphore
{
private:
sem_t m_sema;
Semaphore(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION;
Semaphore& operator=(const Semaphore& other) MOODYCAMEL_DELETE_FUNCTION;
public:
Semaphore(int initialCount = 0)
{
assert(initialCount >= 0);
int rc = sem_init(&m_sema, 0, static_cast<unsigned int>(initialCount));
assert(rc == 0);
(void)rc;
}
~Semaphore()
{
sem_destroy(&m_sema);
}
bool wait()
{
// http://stackoverflow.com/questions/2013181/gdb-causes-sem-wait-to-fail-with-eintr-error
int rc;
do {
rc = sem_wait(&m_sema);
} while (rc == -1 && errno == EINTR);
return rc == 0;
}
bool try_wait()
{
int rc;
do {
rc = sem_trywait(&m_sema);
} while (rc == -1 && errno == EINTR);
return rc == 0;
}
bool timed_wait(std::uint64_t usecs)
{
struct timespec ts;
const int usecs_in_1_sec = 1000000;
const int nsecs_in_1_sec = 1000000000;
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec += (time_t)(usecs / usecs_in_1_sec);
ts.tv_nsec += (long)(usecs % usecs_in_1_sec) * 1000;
// sem_timedwait bombs if you have more than 1e9 in tv_nsec
// so we have to clean things up before passing it in
if (ts.tv_nsec >= nsecs_in_1_sec) {
ts.tv_nsec -= nsecs_in_1_sec;
++ts.tv_sec;
}
int rc;
do {
rc = sem_timedwait(&m_sema, &ts);
} while (rc == -1 && errno == EINTR);
return rc == 0;
}
void signal()
{
while (sem_post(&m_sema) == -1);
}
void signal(int count)
{
while (count-- > 0)
{
while (sem_post(&m_sema) == -1);
}
}
};
#else
#error Unsupported platform! (No semaphore wrapper available)
#endif
} // end namespace details
//---------------------------------------------------------
// LightweightSemaphore
//---------------------------------------------------------
class LightweightSemaphore
{
public:
typedef std::make_signed<std::size_t>::type ssize_t;
private:
std::atomic<ssize_t> m_count;
details::Semaphore m_sema;
int m_maxSpins;
bool waitWithPartialSpinning(std::int64_t timeout_usecs = -1)
{
ssize_t oldCount;
int spin = m_maxSpins;
while (--spin >= 0)
{
oldCount = m_count.load(std::memory_order_relaxed);
if ((oldCount > 0) && m_count.compare_exchange_strong(oldCount, oldCount - 1, std::memory_order_acquire, std::memory_order_relaxed))
return true;
std::atomic_signal_fence(std::memory_order_acquire); // Prevent the compiler from collapsing the loop.
}
oldCount = m_count.fetch_sub(1, std::memory_order_acquire);
if (oldCount > 0)
return true;
if (timeout_usecs < 0)
{
if (m_sema.wait())
return true;
}
if (timeout_usecs > 0 && m_sema.timed_wait((std::uint64_t)timeout_usecs))
return true;
// At this point, we've timed out waiting for the semaphore, but the
// count is still decremented indicating we may still be waiting on
// it. So we have to re-adjust the count, but only if the semaphore
// wasn't signaled enough times for us too since then. If it was, we
// need to release the semaphore too.
while (true)
{
oldCount = m_count.load(std::memory_order_acquire);
if (oldCount >= 0 && m_sema.try_wait())
return true;
if (oldCount < 0 && m_count.compare_exchange_strong(oldCount, oldCount + 1, std::memory_order_relaxed, std::memory_order_relaxed))
return false;
}
}
ssize_t waitManyWithPartialSpinning(ssize_t max, std::int64_t timeout_usecs = -1)
{
assert(max > 0);
ssize_t oldCount;
int spin = m_maxSpins;
while (--spin >= 0)
{
oldCount = m_count.load(std::memory_order_relaxed);
if (oldCount > 0)
{
ssize_t newCount = oldCount > max ? oldCount - max : 0;
if (m_count.compare_exchange_strong(oldCount, newCount, std::memory_order_acquire, std::memory_order_relaxed))
return oldCount - newCount;
}
std::atomic_signal_fence(std::memory_order_acquire);
}
oldCount = m_count.fetch_sub(1, std::memory_order_acquire);
if (oldCount <= 0)
{
if ((timeout_usecs == 0) || (timeout_usecs < 0 && !m_sema.wait()) || (timeout_usecs > 0 && !m_sema.timed_wait((std::uint64_t)timeout_usecs)))
{
while (true)
{
oldCount = m_count.load(std::memory_order_acquire);
if (oldCount >= 0 && m_sema.try_wait())
break;
if (oldCount < 0 && m_count.compare_exchange_strong(oldCount, oldCount + 1, std::memory_order_relaxed, std::memory_order_relaxed))
return 0;
}
}
}
if (max > 1)
return 1 + tryWaitMany(max - 1);
return 1;
}
public:
LightweightSemaphore(ssize_t initialCount = 0, int maxSpins = 10000) : m_count(initialCount), m_maxSpins(maxSpins)
{
assert(initialCount >= 0);
assert(maxSpins >= 0);
}
bool tryWait()
{
ssize_t oldCount = m_count.load(std::memory_order_relaxed);
while (oldCount > 0)
{
if (m_count.compare_exchange_weak(oldCount, oldCount - 1, std::memory_order_acquire, std::memory_order_relaxed))
return true;
}
return false;
}
bool wait()
{
return tryWait() || waitWithPartialSpinning();
}
bool wait(std::int64_t timeout_usecs)
{
return tryWait() || waitWithPartialSpinning(timeout_usecs);
}
// Acquires between 0 and (greedily) max, inclusive
ssize_t tryWaitMany(ssize_t max)
{
assert(max >= 0);
ssize_t oldCount = m_count.load(std::memory_order_relaxed);
while (oldCount > 0)
{
ssize_t newCount = oldCount > max ? oldCount - max : 0;
if (m_count.compare_exchange_weak(oldCount, newCount, std::memory_order_acquire, std::memory_order_relaxed))
return oldCount - newCount;
}
return 0;
}
// Acquires at least one, and (greedily) at most max
ssize_t waitMany(ssize_t max, std::int64_t timeout_usecs)
{
assert(max >= 0);
ssize_t result = tryWaitMany(max);
if (result == 0 && max > 0)
result = waitManyWithPartialSpinning(max, timeout_usecs);
return result;
}
ssize_t waitMany(ssize_t max)
{
ssize_t result = waitMany(max, -1);
assert(result > 0);
return result;
}
void signal(ssize_t count = 1)
{
assert(count >= 0);
ssize_t oldCount = m_count.fetch_add(count, std::memory_order_release);
ssize_t toRelease = -oldCount < count ? -oldCount : count;
if (toRelease > 0)
{
m_sema.signal((int)toRelease);
}
}
std::size_t availableApprox() const
{
ssize_t count = m_count.load(std::memory_order_relaxed);
return count > 0 ? static_cast<std::size_t>(count) : 0;
}
};
} // end namespace moodycamel

View File

@ -47,8 +47,6 @@
#include "llstring.h"
#include "lleventtimer.h"
#include "google_breakpad/exception_handler.h"
#include "stringize.h"
#include "llcleanup.h"
#include "llevents.h"
@ -64,12 +62,6 @@
LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop);
BOOL ConsoleCtrlHandler(DWORD fdwCtrlType);
bool windows_post_minidump_callback(const wchar_t* dump_path,
const wchar_t* minidump_id,
void* context,
EXCEPTION_POINTERS* exinfo,
MDRawAssertionInfo* assertion,
bool succeeded);
#else
# include <signal.h>
# include <unistd.h> // for fork()
@ -77,10 +69,6 @@ void setup_signals();
void default_unix_signal_handler(int signum, siginfo_t *info, void *);
#if LL_LINUX
#include "google_breakpad/minidump_descriptor.h"
static bool unix_minidump_callback(const google_breakpad::MinidumpDescriptor& minidump_desc,
void* context,
bool succeeded);
#else
// Called by breakpad exception handler after the minidump has been generated.
bool unix_post_minidump_callback(const char *dump_dir,
@ -115,7 +103,8 @@ BOOL LLApp::sDisableCrashlogger = FALSE;
BOOL LLApp::sLogInSignal = FALSE;
// static
LLApp::EAppStatus LLApp::sStatus = LLApp::APP_STATUS_STOPPED; // Keeps track of application status
// Keeps track of application status
LLScalarCond<LLApp::EAppStatus> LLApp::sStatus{LLApp::APP_STATUS_STOPPED};
LLAppErrorHandler LLApp::sErrorHandler = NULL;
BOOL LLApp::sErrorThreadRunning = FALSE;
@ -148,8 +137,6 @@ void LLApp::commonCtor()
// Set the application to this instance.
sApplication = this;
mExceptionHandler = 0;
// initialize the buffer to write the minidump filename to
// (this is used to avoid allocating memory in the crash handler)
@ -179,8 +166,6 @@ LLApp::~LLApp()
delete mThreadErrorp;
mThreadErrorp = NULL;
}
if(mExceptionHandler != 0) delete mExceptionHandler;
SUBSYSTEM_CLEANUP_DBG(LLCommon);
}
@ -396,140 +381,18 @@ void LLApp::setupErrorHandling(bool second_instance)
#if LL_WINDOWS
#if LL_SEND_CRASH_REPORTS && ! defined(LL_BUGSPLAT)
EnableCrashingOnCrashes();
// This sets a callback to handle w32 signals to the console window.
// The viewer shouldn't be affected, sicne its a windowed app.
SetConsoleCtrlHandler( (PHANDLER_ROUTINE) ConsoleCtrlHandler, TRUE);
// Install the Google Breakpad crash handler for Windows
if(mExceptionHandler == 0)
{
if ( second_instance ) //BUG-5707 Firing teleport from a web browser causes second
{
mExceptionHandler = new google_breakpad::ExceptionHandler(
L"C:\\Temp\\",
0, //No filter
windows_post_minidump_callback,
0,
google_breakpad::ExceptionHandler::HANDLER_ALL); //No custom client info.
}
else
{
LL_WARNS() << "adding breakpad exception handler" << LL_ENDL;
std::wstring wpipe_name;
wpipe_name = mCrashReportPipeStr + wstringize(getPid());
const std::wstring wdump_path(utf8str_to_utf16str(mDumpPath));
int retries = 30;
for (; retries > 0; --retries)
{
if (mExceptionHandler != 0) delete mExceptionHandler;
U32 maskMiniDumpType = MiniDumpNormal | MiniDumpFilterModulePaths;
mExceptionHandler = new google_breakpad::ExceptionHandler(
wdump_path,
NULL, //No filter
windows_post_minidump_callback,
0,
google_breakpad::ExceptionHandler::HANDLER_ALL,
// MiniDumpNormal, //Generate a 'normal' minidump.
(MINIDUMP_TYPE)maskMiniDumpType, // <FS:ND/> Pass custom minidump type from prefs to breakpad.
wpipe_name.c_str(),
NULL); //No custom client info.
if (mExceptionHandler->IsOutOfProcess())
{
LL_INFOS("CRASHREPORT") << "Successfully attached to Out of Process exception handler." << LL_ENDL;
break;
}
else
{
LL_WARNS("CRASHREPORT") << "Unable to attach to Out of Process exception handler. " << retries << " retries remaining." << LL_ENDL;
::Sleep(100); //Wait a tick and try again.
}
}
if (retries == 0) LL_WARNS("CRASHREPORT") << "Unable to attach to Out of Process exception handler." << LL_ENDL;
}
if (mExceptionHandler)
{
mExceptionHandler->set_handle_debug_exceptions(true);
}
}
#endif // LL_SEND_CRASH_REPORTS && ! defined(LL_BUGSPLAT)
#else // ! LL_WINDOWS
#if defined(LL_BUGSPLAT)
// Don't install our own signal handlers -- BugSplat needs to hook them,
// or it's completely ineffectual.
bool installHandler = false;
#else // ! LL_BUGSPLAT
//
// Start up signal handling.
//
// There are two different classes of signals. Synchronous signals are delivered to a specific
// thread, asynchronous signals can be delivered to any thread (in theory)
//
setup_signals();
// Add google breakpad exception handler configured for Darwin/Linux.
bool installHandler = true;
#if ! defined(LL_BUGSPLAT)
//
// Start up signal handling.
//
// There are two different classes of signals. Synchronous signals are delivered to a specific
// thread, asynchronous signals can be delivered to any thread (in theory)
//
setup_signals();
#endif // ! LL_BUGSPLAT
#if LL_DARWIN
// For the special case of Darwin, we do not want to install the handler if
// the process is being debugged as the app will exit with value ABRT (6) if
// we do. Unfortunately, the code below which performs that test relies on
// the structure kinfo_proc which has been tagged by apple as an unstable
// API. We disable this test for shipping versions to avoid conflicts with
// future releases of Darwin. This test is really only needed for developers
// starting the app from a debugger anyway.
#ifndef LL_RELEASE_FOR_DOWNLOAD
int mib[4];
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PID;
mib[3] = getpid();
struct kinfo_proc info;
memset(&info, 0, sizeof(info));
size_t size = sizeof(info);
int result = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);
if((result == 0) || (errno == ENOMEM))
{
// P_TRACED flag is set, so this process is being debugged; do not install
// the handler
if(info.kp_proc.p_flag & P_TRACED) installHandler = false;
}
else
{
// Failed to discover if the process is being debugged; default to
// installing the handler.
installHandler = true;
}
#endif // ! LL_RELEASE_FOR_DOWNLOAD
if(installHandler && (mExceptionHandler == 0))
{
mExceptionHandler = new google_breakpad::ExceptionHandler(mDumpPath, 0, &unix_post_minidump_callback, 0, true, 0);
}
#elif LL_LINUX
if(installHandler && (mExceptionHandler == 0))
{
if (mDumpPath.empty())
{
mDumpPath = "/tmp";
}
google_breakpad::MinidumpDescriptor desc(mDumpPath);
mExceptionHandler = new google_breakpad::ExceptionHandler(desc, NULL, unix_minidump_callback, NULL, true, -1);
}
#endif // LL_LINUX
#endif // ! LL_WINDOWS
#ifdef LL_BUGSPLAT
@ -587,7 +450,8 @@ static std::map<LLApp::EAppStatus, const char*> statusDesc
// static
void LLApp::setStatus(EAppStatus status)
{
sStatus = status;
// notify everyone waiting on sStatus any time its value changes
sStatus.set_all(status);
// This can also happen very late in the application lifecycle -- don't
// resurrect a deleted LLSingleton
@ -617,29 +481,10 @@ void LLApp::setError()
setStatus(APP_STATUS_ERROR);
}
void LLApp::setMiniDumpDir(const std::string &path)
// static
bool LLApp::sleep(F32Milliseconds duration)
{
if (path.empty())
{
mDumpPath = "/tmp";
}
else
{
mDumpPath = path;
}
if(mExceptionHandler == 0) return;
#ifdef LL_WINDOWS
std::wstring buffer(utf8str_to_utf16str(mDumpPath));
if (buffer.size() > MAX_MINDUMP_PATH_LENGTH) buffer.resize(MAX_MINDUMP_PATH_LENGTH);
mExceptionHandler->set_dump_path(buffer);
#elif LL_LINUX
//google_breakpad::MinidumpDescriptor desc("/tmp"); //path works in debug fails in production inside breakpad lib so linux gets a little less stack reporting until it is patched.
google_breakpad::MinidumpDescriptor desc(mDumpPath); //path works in debug fails in production inside breakpad lib so linux gets a little less stack reporting until it is patched.
mExceptionHandler->set_minidump_descriptor(desc);
#else
mExceptionHandler->set_dump_path(mDumpPath);
#endif
return ! sStatus.wait_for_unequal(duration, APP_STATUS_RUNNING);
}
void LLApp::setDebugFileNames(const std::string &path)
@ -650,8 +495,6 @@ void LLApp::setDebugFileNames(const std::string &path)
void LLApp::writeMiniDump()
{
if(mExceptionHandler == 0) return;
mExceptionHandler->WriteMinidump();
}
// static
@ -676,28 +519,28 @@ void LLApp::setStopped()
// static
bool LLApp::isStopped()
{
return (APP_STATUS_STOPPED == sStatus);
return (APP_STATUS_STOPPED == sStatus.get());
}
// static
bool LLApp::isRunning()
{
return (APP_STATUS_RUNNING == sStatus);
return (APP_STATUS_RUNNING == sStatus.get());
}
// static
bool LLApp::isError()
{
return (APP_STATUS_ERROR == sStatus);
return (APP_STATUS_ERROR == sStatus.get());
}
// static
bool LLApp::isQuitting()
{
return (APP_STATUS_QUITTING == sStatus);
return (APP_STATUS_QUITTING == sStatus.get());
}
// static
@ -708,13 +551,6 @@ bool LLApp::isExiting()
void LLApp::disableCrashlogger()
{
// Disable Breakpad exception handler.
if (mExceptionHandler != 0)
{
delete mExceptionHandler;
mExceptionHandler = 0;
}
sDisableCrashlogger = TRUE;
}
@ -1022,48 +858,6 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *)
}
}
#if LL_LINUX
bool unix_minidump_callback(const google_breakpad::MinidumpDescriptor& minidump_desc, void* context, bool succeeded)
{
// Copy minidump file path into fixed buffer in the app instance to avoid
// heap allocations in a crash handler.
// path format: <dump_dir>/<minidump_id>.dmp
//HACK: *path points to the buffer in getMiniDumpFilename which has already allocated space
//to avoid doing allocation during crash.
char * path = LLApp::instance()->getMiniDumpFilename();
int dir_path_len = strlen(path);
// The path must not be truncated.
S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH - dir_path_len;
llassert( (remaining - strlen(minidump_desc.path())) > 5);
path += dir_path_len;
if (dir_path_len > 0 && path[-1] != '/')
{
*path++ = '/';
--remaining;
}
strncpy(path, minidump_desc.path(), remaining);
LL_INFOS("CRASHREPORT") << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << LL_ENDL;
LLApp::runErrorHandler();
#ifndef LL_RELEASE_FOR_DOWNLOAD
clear_signals();
return false;
#else
return true;
#endif
}
#endif
bool unix_post_minidump_callback(const char *dump_dir,
const char *minidump_id,
void *context, bool succeeded)
@ -1108,129 +902,3 @@ bool unix_post_minidump_callback(const char *dump_dir,
}
#endif // !WINDOWS
#ifdef LL_WINDOWS
// <FS:ND> Helper function to convert a wchar_t string into an UTF8 buffer
namespace nd
{
namespace strings
{
inline bool convertString( wchar_t const *aIn, char *&aOut, S32 &aLen )
{
char tmpBuffer[8];
S32 i(0), j(0);
while( *aIn )
{
i = wchar_to_utf8chars( *aIn++, tmpBuffer );
if( i < aLen )
{
j = 0;
while( j < i )
{
*aOut++ = tmpBuffer[ j++ ];
--aLen;
}
}
else
return true;
}
return false;
}
}
}
// </FS:ND>
bool windows_post_minidump_callback(const wchar_t* dump_path,
const wchar_t* minidump_id,
void* context,
EXCEPTION_POINTERS* exinfo,
MDRawAssertionInfo* assertion,
bool succeeded)
{
// <FS:ND> Convert all path to UTF8 and not MBCS. Having some path in MBCS and some in UTF8 is a source of great joy
// and bugs. Stick with one standard, that is UTF8.
// char * path = LLApp::instance()->getMiniDumpFilename();
// S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH;
// size_t bytesUsed;
// LL_INFOS("MINIDUMPCALLBACK") << "Dump file was generated." << LL_ENDL;
// bytesUsed = wcstombs(path, dump_path, static_cast<size_t>(remaining));
// remaining -= bytesUsed;
// path += bytesUsed;
// if(remaining > 0 && bytesUsed > 0 && path[-1] != '\\')
// {
// *path++ = '\\';
// --remaining;
// }
// if(remaining > 0)
// {
// bytesUsed = wcstombs(path, minidump_id, static_cast<size_t>(remaining));
// remaining -= bytesUsed;
// path += bytesUsed;
// }
// if(remaining > 0)
// {
// strncpy(path, ".dmp", remaining);
// }
char *pOut( LLApp::instance()->getMiniDumpFilename() );
bool hasOverflow( false );
S32 bufferLength( LLApp::MAX_MINDUMP_PATH_LENGTH );
hasOverflow = nd::strings::convertString( dump_path, pOut, bufferLength );
if( !hasOverflow && bufferLength < LLApp::MAX_MINDUMP_PATH_LENGTH && bufferLength > 1 && pOut[-1] != '\\' && pOut[-1] != '/' )
{
*pOut++ = '\\';
--bufferLength;
}
if( !hasOverflow )
hasOverflow = nd::strings::convertString( minidump_id, pOut, bufferLength );
if( !hasOverflow && bufferLength >= 5 )
{
pOut[0] = '.';
pOut[1] = 'd';
pOut[2] = 'm';
pOut[3] = 'p';
pOut[4] = 0;
}
else if( hasOverflow )
LLApp::instance()->getMiniDumpFilename()[ 0 ] = 0;
// </FS:ND>
LL_INFOS("CRASHREPORT") << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << LL_ENDL;
// *NOTE:Mani - this code is stolen from LLApp, where its never actually used.
//OSMessageBox("Attach Debugger Now", "Error", OSMB_OK);
// *TODO: Translate the signals/exceptions into cross-platform stuff
// Windows implementation
LL_INFOS() << "Entering Windows Exception Handler..." << LL_ENDL;
if (LLApp::isError())
{
LL_WARNS() << "Got another fatal signal while in the error handler, die now!" << LL_ENDL;
}
// Flag status to error, so thread_error starts its work
LLApp::setError();
// Block in the exception handler until the app has stopped
// This is pretty sketchy, but appears to work just fine
while (!LLApp::isStopped())
{
ms_sleep(10);
}
#ifndef LL_RELEASE_FOR_DOWNLOAD
return false;
#else
return true;
#endif
}
#endif

View File

@ -28,9 +28,11 @@
#define LL_LLAPP_H
#include <map>
#include "llcond.h"
#include "llrun.h"
#include "llsd.h"
#include <atomic>
#include <chrono>
// Forward declarations
class LLErrorThread;
class LLLiveFile;
@ -49,10 +51,6 @@ void clear_signals();
#endif
namespace google_breakpad {
class ExceptionHandler; // See exception_handler.h
}
class LL_COMMON_API LLApp
{
friend class LLErrorThread;
@ -211,6 +209,36 @@ public:
static bool isExiting(); // Either quitting or error (app is exiting, cleanly or not)
static int getPid();
//
// Sleep for specified time while still running
//
// For use by a coroutine or thread that performs some maintenance on a
// periodic basis. (See also LLEventTimer.) This method supports the
// pattern of an "infinite" loop that sleeps for some time, performs some
// action, then sleeps again. The trouble with literally sleeping a worker
// thread is that it could potentially sleep right through attempted
// application shutdown. This method avoids that by returning false as
// soon as the application status changes away from APP_STATUS_RUNNING
// (isRunning()).
//
// sleep() returns true if it sleeps undisturbed for the entire specified
// duration. The idea is that you can code 'while sleep(duration) ...',
// which will break the loop once shutdown begins.
//
// Since any time-based LLUnit should be implicitly convertible to
// F32Milliseconds, accept that specific type as a proxy.
static bool sleep(F32Milliseconds duration);
// Allow any duration defined in terms of <chrono>.
// One can imagine a wonderfully general bidirectional conversion system
// between any type derived from LLUnits::LLUnit<T, LLUnits::Seconds> and
// any std::chrono::duration -- but that doesn't yet exist.
template <typename Rep, typename Period>
bool sleep(const std::chrono::duration<Rep, Period>& duration)
{
// wait_for_unequal() has the opposite bool return convention
return ! sStatus.wait_for_unequal(duration, APP_STATUS_RUNNING);
}
/** @name Error handling methods */
//@{
/**
@ -236,13 +264,12 @@ public:
static const U32 MAX_MINDUMP_PATH_LENGTH = 256;
// change the directory where Breakpad minidump files are written to
void setMiniDumpDir(const std::string &path);
void setDebugFileNames(const std::string &path);
// Return the Google Breakpad minidump filename after a crash.
char *getMiniDumpFilename() { return mMinidumpPath; }
std::string* getStaticDebugFile() { return &mStaticDebugFileName; }
std::string* getDynamicDebugFile() { return &mDynamicDebugFileName; }
std::string* getStaticDebugFile() { return &mStaticDebugFileName; }
std::string* getDynamicDebugFile() { return &mDynamicDebugFileName; }
// Write out a Google Breakpad minidump file.
void writeMiniDump();
@ -270,7 +297,7 @@ public:
protected:
static void setStatus(EAppStatus status); // Use this to change the application status.
static EAppStatus sStatus; // Reflects current application status
static LLScalarCond<EAppStatus> sStatus; // Reflects current application status
static BOOL sErrorThreadRunning; // Set while the error thread is running
static BOOL sDisableCrashlogger; // Let the OS handle crashes for us.
std::wstring mCrashReportPipeStr; //Name of pipe to use for crash reporting.
@ -316,9 +343,6 @@ private:
private:
// the static application instance if it was created.
static LLApp* sApplication;
google_breakpad::ExceptionHandler * mExceptionHandler;
#if !LL_WINDOWS
friend void default_unix_signal_handler(int signum, siginfo_t *info, void *);

View File

@ -134,6 +134,13 @@ LLCoros::LLCoros():
LLCoros::~LLCoros()
{
}
void LLCoros::cleanupSingleton()
{
// Some of the coroutines (like voice) will depend onto
// origin singletons, so clean coros before deleting those
printActiveCoroutines("at entry to ~LLCoros()");
// Other LLApp status-change listeners do things like close
// work queues and inject the Stop exception into pending
@ -149,6 +156,8 @@ LLCoros::~LLCoros()
{
// don't use llcoro::suspend() because that module depends
// on this one
// This will yield current(main) thread and will let active
// corutines run once
boost::this_fiber::yield();
}
printActiveCoroutines("after pumping");

View File

@ -89,6 +89,8 @@ class LL_COMMON_API LLCoros: public LLSingleton<LLCoros>
{
LLSINGLETON(LLCoros);
~LLCoros();
void cleanupSingleton();
public:
/// The viewer's use of the term "coroutine" became deeply embedded before
/// the industry term "fiber" emerged to distinguish userland threads from

View File

@ -481,6 +481,62 @@ namespace
typedef std::vector<LLError::RecorderPtr> Recorders;
typedef std::vector<LLError::CallSite*> CallSiteVector;
class SettingsConfig : public LLRefCount
{
friend class Globals;
public:
virtual ~SettingsConfig();
LLError::ELevel mDefaultLevel;
bool mLogAlwaysFlush;
U32 mEnabledLogTypesMask;
LevelMap mFunctionLevelMap;
LevelMap mClassLevelMap;
LevelMap mFileLevelMap;
LevelMap mTagLevelMap;
std::map<std::string, unsigned int> mUniqueLogMessages;
LLError::FatalFunction mCrashFunction;
LLError::TimeFunction mTimeFunction;
Recorders mRecorders;
LLMutex mRecorderMutex;
int mShouldLogCallCounter;
private:
SettingsConfig();
};
typedef LLPointer<SettingsConfig> SettingsConfigPtr;
SettingsConfig::SettingsConfig()
: LLRefCount(),
mDefaultLevel(LLError::LEVEL_DEBUG),
mLogAlwaysFlush(true),
mEnabledLogTypesMask(255),
mFunctionLevelMap(),
mClassLevelMap(),
mFileLevelMap(),
mTagLevelMap(),
mUniqueLogMessages(),
mCrashFunction(NULL),
mTimeFunction(NULL),
mRecorders(),
mRecorderMutex(),
mShouldLogCallCounter(0)
{
}
SettingsConfig::~SettingsConfig()
{
mRecorders.clear();
}
class Globals
{
public:
@ -488,16 +544,28 @@ namespace
protected:
Globals();
public:
std::ostringstream messageStream;
bool messageStreamInUse;
std::string mFatalMessage;
void addCallSite(LLError::CallSite&);
void invalidateCallSites();
SettingsConfigPtr getSettingsConfig();
void resetSettingsConfig();
LLError::SettingsStoragePtr saveAndResetSettingsConfig();
void restore(LLError::SettingsStoragePtr pSettingsStorage);
private:
CallSiteVector callSites;
SettingsConfigPtr mSettingsConfig;
};
Globals::Globals() {}
Globals::Globals()
: mSettingsConfig(new SettingsConfig())
{
}
Globals* Globals::getInstance()
{
@ -525,120 +593,31 @@ namespace
callSites.clear();
}
}
namespace LLError
{
class SettingsConfig : public LLRefCount
{
friend class Settings;
public:
virtual ~SettingsConfig();
LLError::ELevel mDefaultLevel;
bool mLogAlwaysFlush;
U32 mEnabledLogTypesMask;
LevelMap mFunctionLevelMap;
LevelMap mClassLevelMap;
LevelMap mFileLevelMap;
LevelMap mTagLevelMap;
std::map<std::string, unsigned int> mUniqueLogMessages;
LLError::FatalFunction mCrashFunction;
LLError::TimeFunction mTimeFunction;
Recorders mRecorders;
int mShouldLogCallCounter;
private:
SettingsConfig();
};
typedef LLPointer<SettingsConfig> SettingsConfigPtr;
class Settings
{
public:
static Settings* getInstance();
protected:
Settings();
public:
SettingsConfigPtr getSettingsConfig();
void reset();
SettingsStoragePtr saveAndReset();
void restore(SettingsStoragePtr pSettingsStorage);
private:
SettingsConfigPtr mSettingsConfig;
};
SettingsConfig::SettingsConfig()
: LLRefCount(),
mDefaultLevel(LLError::LEVEL_DEBUG),
mLogAlwaysFlush(true),
mEnabledLogTypesMask(255),
mFunctionLevelMap(),
mClassLevelMap(),
mFileLevelMap(),
mTagLevelMap(),
mUniqueLogMessages(),
mCrashFunction([](const std::string&){}),
mTimeFunction(NULL),
mRecorders(),
mShouldLogCallCounter(0)
{
}
SettingsConfig::~SettingsConfig()
{
mRecorders.clear();
}
Settings::Settings():
mSettingsConfig(new SettingsConfig())
{
}
Settings* Settings::getInstance()
SettingsConfigPtr Globals::getSettingsConfig()
{
// According to C++11 Function-Local Initialization
// of static variables is supposed to be thread safe
// without risk of deadlocks.
static Settings inst;
return &inst;
return mSettingsConfig;
}
SettingsConfigPtr Settings::getSettingsConfig()
{
return mSettingsConfig;
}
void Globals::resetSettingsConfig()
{
invalidateCallSites();
mSettingsConfig = new SettingsConfig();
}
void Settings::reset()
{
Globals::getInstance()->invalidateCallSites();
mSettingsConfig = new SettingsConfig();
}
LLError::SettingsStoragePtr Globals::saveAndResetSettingsConfig()
{
LLError::SettingsStoragePtr oldSettingsConfig(mSettingsConfig.get());
resetSettingsConfig();
return oldSettingsConfig;
}
SettingsStoragePtr Settings::saveAndReset()
{
SettingsStoragePtr oldSettingsConfig(mSettingsConfig.get());
reset();
return oldSettingsConfig;
}
void Settings::restore(SettingsStoragePtr pSettingsStorage)
{
Globals::getInstance()->invalidateCallSites();
SettingsConfigPtr newSettingsConfig(dynamic_cast<SettingsConfig *>(pSettingsStorage.get()));
mSettingsConfig = newSettingsConfig;
}
void Globals::restore(LLError::SettingsStoragePtr pSettingsStorage)
{
invalidateCallSites();
SettingsConfigPtr newSettingsConfig(dynamic_cast<SettingsConfig *>(pSettingsStorage.get()));
mSettingsConfig = newSettingsConfig;
}
}
namespace LLError
@ -768,7 +747,7 @@ namespace
void commonInit(const std::string& user_dir, const std::string& app_dir, bool log_to_stderr = true)
{
LLError::Settings::getInstance()->reset();
Globals::getInstance()->resetSettingsConfig();
LLError::setDefaultLevel(LLError::LEVEL_INFO);
LLError::setAlwaysFlush(true);
@ -809,13 +788,13 @@ namespace LLError
void setFatalFunction(const FatalFunction& f)
{
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
s->mCrashFunction = f;
}
FatalFunction getFatalFunction()
{
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
return s->mCrashFunction;
}
@ -826,72 +805,77 @@ namespace LLError
void setTimeFunction(TimeFunction f)
{
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
s->mTimeFunction = f;
}
void setDefaultLevel(ELevel level)
{
Globals::getInstance()->invalidateCallSites();
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
Globals *g = Globals::getInstance();
g->invalidateCallSites();
SettingsConfigPtr s = g->getSettingsConfig();
s->mDefaultLevel = level;
}
ELevel getDefaultLevel()
{
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
return s->mDefaultLevel;
}
void setAlwaysFlush(bool flush)
{
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
s->mLogAlwaysFlush = flush;
}
bool getAlwaysFlush()
{
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
return s->mLogAlwaysFlush;
}
void setEnabledLogTypesMask(U32 mask)
{
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
s->mEnabledLogTypesMask = mask;
}
U32 getEnabledLogTypesMask()
{
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
return s->mEnabledLogTypesMask;
}
void setFunctionLevel(const std::string& function_name, ELevel level)
{
Globals::getInstance()->invalidateCallSites();
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
Globals *g = Globals::getInstance();
g->invalidateCallSites();
SettingsConfigPtr s = g->getSettingsConfig();
s->mFunctionLevelMap[function_name] = level;
}
void setClassLevel(const std::string& class_name, ELevel level)
{
Globals::getInstance()->invalidateCallSites();
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
Globals *g = Globals::getInstance();
g->invalidateCallSites();
SettingsConfigPtr s = g->getSettingsConfig();
s->mClassLevelMap[class_name] = level;
}
void setFileLevel(const std::string& file_name, ELevel level)
{
Globals::getInstance()->invalidateCallSites();
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
Globals *g = Globals::getInstance();
g->invalidateCallSites();
SettingsConfigPtr s = g->getSettingsConfig();
s->mFileLevelMap[file_name] = level;
}
void setTagLevel(const std::string& tag_name, ELevel level)
{
Globals::getInstance()->invalidateCallSites();
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
Globals *g = Globals::getInstance();
g->invalidateCallSites();
SettingsConfigPtr s = g->getSettingsConfig();
s->mTagLevelMap[tag_name] = level;
}
@ -936,8 +920,9 @@ namespace LLError
{
void configure(const LLSD& config)
{
Globals::getInstance()->invalidateCallSites();
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
Globals *g = Globals::getInstance();
g->invalidateCallSites();
SettingsConfigPtr s = g->getSettingsConfig();
s->mFunctionLevelMap.clear();
s->mClassLevelMap.clear();
@ -1064,7 +1049,8 @@ namespace LLError
{
return;
}
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
LLMutexLock lock(&s->mRecorderMutex);
s->mRecorders.push_back(recorder);
}
@ -1074,7 +1060,8 @@ namespace LLError
{
return;
}
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
LLMutexLock lock(&s->mRecorderMutex);
s->mRecorders.erase(std::remove(s->mRecorders.begin(), s->mRecorders.end(), recorder),
s->mRecorders.end());
}
@ -1086,11 +1073,12 @@ namespace LLError
// with a Recorders::iterator indicating the position of that entry in
// mRecorders. The shared_ptr might be empty (operator!() returns true) if
// there was no such RECORDER subclass instance in mRecorders.
//
// NOTE!!! Requires external mutex lock!!!
template <typename RECORDER>
std::pair<boost::shared_ptr<RECORDER>, Recorders::iterator>
findRecorderPos()
findRecorderPos(SettingsConfigPtr &s)
{
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
// Since we promise to return an iterator, use a classic iterator
// loop.
auto end{s->mRecorders.end()};
@ -1121,7 +1109,9 @@ namespace LLError
template <typename RECORDER>
boost::shared_ptr<RECORDER> findRecorder()
{
return findRecorderPos<RECORDER>().first;
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
LLMutexLock lock(&s->mRecorderMutex);
return findRecorderPos<RECORDER>(s).first;
}
// Remove an entry from SettingsConfig::mRecorders whose RecorderPtr
@ -1130,10 +1120,11 @@ namespace LLError
template <typename RECORDER>
bool removeRecorder()
{
auto found = findRecorderPos<RECORDER>();
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
LLMutexLock lock(&s->mRecorderMutex);
auto found = findRecorderPos<RECORDER>(s);
if (found.first)
{
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
s->mRecorders.erase(found.second);
}
return bool(found.first);
@ -1231,10 +1222,11 @@ namespace
void writeToRecorders(const LLError::CallSite& site, const std::string& message)
{
LLError::ELevel level = site.mLevel;
LLError::SettingsConfigPtr s = LLError::Settings::getInstance()->getSettingsConfig();
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
std::string escaped_message;
LLMutexLock lock(&s->mRecorderMutex);
for (Recorders::const_iterator i = s->mRecorders.begin();
i != s->mRecorders.end();
++i)
@ -1376,7 +1368,8 @@ namespace LLError
return false;
}
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
Globals *g = Globals::getInstance();
SettingsConfigPtr s = g->getSettingsConfig();
s->mShouldLogCallCounter++;
@ -1406,7 +1399,7 @@ namespace LLError
: false);
site.mCached = true;
Globals::getInstance()->addCallSite(site);
g->addCallSite(site);
return site.mShouldLog = site.mLevel >= compareLevel;
}
@ -1420,7 +1413,7 @@ namespace LLError
}
Globals* g = Globals::getInstance();
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
SettingsConfigPtr s = g->getSettingsConfig();
std::string message = out.str();
@ -1465,12 +1458,12 @@ namespace LLError
{
SettingsStoragePtr saveAndResetSettings()
{
return Settings::getInstance()->saveAndReset();
return Globals::getInstance()->saveAndResetSettingsConfig();
}
void restoreSettings(SettingsStoragePtr pSettingsStorage)
{
return Settings::getInstance()->restore(pSettingsStorage);
return Globals::getInstance()->restore(pSettingsStorage);
}
std::string removePrefix(std::string& s, const std::string& p)
@ -1516,7 +1509,7 @@ namespace LLError
int shouldLogCallCount()
{
SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
return s->mShouldLogCallCounter;
}
@ -1628,8 +1621,8 @@ bool debugLoggingEnabled(const std::string& tag)
{
return false;
}
LLError::SettingsConfigPtr s = LLError::Settings::getInstance()->getSettingsConfig();
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
LLError::ELevel level = LLError::LEVEL_DEBUG;
bool res = checkLevelMap(s->mTagLevelMap, tag, level);
return res;

View File

@ -45,7 +45,6 @@
#include <cctype>
// external library headers
#include <boost/range/iterator_range.hpp>
#include <boost/make_shared.hpp>
#if LL_WINDOWS
#pragma warning (push)
#pragma warning (disable : 4701) // compiler thinks might use uninitialized var, but no
@ -285,7 +284,7 @@ LLEventPump::LLEventPump(const std::string& name, bool tweak):
// Register every new instance with LLEventPumps
mRegistry(LLEventPumps::instance().getHandle()),
mName(mRegistry.get()->registerNew(*this, name, tweak)),
mSignal(boost::make_shared<LLStandardSignal>()),
mSignal(std::make_shared<LLStandardSignal>()),
mEnabled(true)
{}
@ -317,14 +316,24 @@ void LLEventPump::clear()
{
// Destroy the original LLStandardSignal instance, replacing it with a
// whole new one.
mSignal = boost::make_shared<LLStandardSignal>();
mSignal = std::make_shared<LLStandardSignal>();
mConnections.clear();
}
void LLEventPump::reset()
{
mSignal.reset();
// Resetting mSignal is supposed to disconnect everything on its own
// But due to crash on 'reset' added explicit cleanup to get more data
ConnectionMap::const_iterator iter = mConnections.begin();
ConnectionMap::const_iterator end = mConnections.end();
while (iter!=end)
{
iter->second.disconnect();
iter++;
}
mConnections.clear();
mSignal.reset();
//mDeps.clear();
}
@ -543,7 +552,7 @@ bool LLEventStream::post(const LLSD& event)
// *stack* instance of the shared_ptr, ensuring that our heap
// LLStandardSignal object will live at least until post() returns, even
// if 'this' gets destroyed during the call.
boost::shared_ptr<LLStandardSignal> signal(mSignal);
std::shared_ptr<LLStandardSignal> signal(mSignal);
// Let caller know if any one listener handled the event. This is mostly
// useful when using LLEventStream as a listener for an upstream
// LLEventPump.

View File

@ -49,8 +49,6 @@
#endif
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/utility.hpp> // noncopyable
#include <boost/optional/optional.hpp>
#include <boost/visit_each.hpp>
@ -571,7 +569,7 @@ protected:
const NameList& before);
/// implement the dispatching
boost::shared_ptr<LLStandardSignal> mSignal;
std::shared_ptr<LLStandardSignal> mSignal;
/// valve open?
bool mEnabled;
@ -745,14 +743,4 @@ private:
LL_COMMON_API bool sendReply(const LLSD& reply, const LLSD& request,
const std::string& replyKey="reply");
// Somewhat to my surprise, passing boost::bind(...boost::weak_ptr<T>...) to
// listen() fails in Boost code trying to instantiate LLEventListener (i.e.
// LLStandardSignal::slot_type) because the boost::get_pointer() utility function isn't
// specialized for boost::weak_ptr. This remedies that omission.
namespace boost
{
template <typename T>
T* get_pointer(const weak_ptr<T>& ptr) { return shared_ptr<T>(ptr).get(); }
}
#endif /* ! defined(LL_LLEVENTS_H) */

View File

@ -40,6 +40,12 @@
#define LL_BIG_ENDIAN 1
#endif
//<FS:ND> FIRE-31221 workaround for newer glibc versions, patch from Lance Corrimal
// Figure out GLIBC version - 2.34 needs an additional include as a build fix
#if (__GLIBC__*1000 + __GLIBC_MINOR__) >= 2034
#include <bits/pthread_stack_min.h>
#endif
// </FS:Nd>
// Per-compiler switches

89
indra/llcommon/llregex.h Normal file
View File

@ -0,0 +1,89 @@
/**
* @file llregex.h
*
* $LicenseInfo:firstyear=2021&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2021, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LLREGEX_H
#define LLREGEX_H
#include <boost/regex.hpp>
template <typename S, typename M, typename R>
LL_COMMON_API bool ll_regex_match(const S& string, M& match, const R& regex)
{
try
{
return boost::regex_match(string, match, regex);
}
catch (const std::runtime_error& e)
{
LL_WARNS() << "error matching with '" << regex.str() << "': "
<< e.what() << ":\n'" << string << "'" << LL_ENDL;
return false;
}
}
template <typename S, typename R>
LL_COMMON_API bool ll_regex_match(const S& string, const R& regex)
{
try
{
return boost::regex_match(string, regex);
}
catch (const std::runtime_error& e)
{
LL_WARNS() << "error matching with '" << regex.str() << "': "
<< e.what() << ":\n'" << string << "'" << LL_ENDL;
return false;
}
}
template <typename S, typename M, typename R>
bool ll_regex_search(const S& string, M& match, const R& regex)
{
try
{
return boost::regex_search(string, match, regex);
}
catch (const std::runtime_error& e)
{
LL_WARNS() << "error searching with '" << regex.str() << "': "
<< e.what() << ":\n'" << string << "'" << LL_ENDL;
return false;
}
}
template <typename S, typename R>
bool ll_regex_search(const S& string, const R& regex)
{
try
{
return boost::regex_search(string, regex);
}
catch (const std::runtime_error& e)
{
LL_WARNS() << "error searching with '" << regex.str() << "': "
<< e.what() << ":\n'" << string << "'" << LL_ENDL;
return false;
}
}
#endif // LLREGEX_H

View File

@ -43,12 +43,12 @@
#include "llerrorcontrol.h"
#include "llevents.h"
#include "llformat.h"
#include "llregex.h"
#include "lltimer.h"
#include "llsdserialize.h"
#include "llsdutil.h"
#include <boost/bind.hpp>
#include <boost/circular_buffer.hpp>
#include <boost/regex.hpp>
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/range.hpp>
@ -101,39 +101,6 @@ static const F32 MEM_INFO_THROTTLE = 20;
// dropped below the login framerate, we'd have very little additional data.
static const F32 MEM_INFO_WINDOW = 10*60;
// Wrap boost::regex_match() with a function that doesn't throw.
template <typename S, typename M, typename R>
static bool regex_match_no_exc(const S& string, M& match, const R& regex)
{
try
{
return boost::regex_match(string, match, regex);
}
catch (const std::runtime_error& e)
{
LL_WARNS("LLMemoryInfo") << "error matching with '" << regex.str() << "': "
<< e.what() << ":\n'" << string << "'" << LL_ENDL;
return false;
}
}
// Wrap boost::regex_search() with a function that doesn't throw.
template <typename S, typename M, typename R>
static bool regex_search_no_exc(const S& string, M& match, const R& regex)
{
try
{
return boost::regex_search(string, match, regex);
}
catch (const std::runtime_error& e)
{
LL_WARNS("LLMemoryInfo") << "error searching with '" << regex.str() << "': "
<< e.what() << ":\n'" << string << "'" << LL_ENDL;
return false;
}
}
LLOSInfo::LLOSInfo() :
mMajorVer(0), mMinorVer(0), mBuild(0), mOSVersionString("")
{
@ -384,7 +351,7 @@ LLOSInfo::LLOSInfo() :
boost::smatch matched;
std::string glibc_version(gnu_get_libc_version());
if ( regex_match_no_exc(glibc_version, matched, os_version_parse) )
if ( ll_regex_match(glibc_version, matched, os_version_parse) )
{
LL_INFOS("AppInit") << "Using glibc version '" << glibc_version << "' as OS version" << LL_ENDL;
@ -1061,7 +1028,7 @@ LLSD LLMemoryInfo::loadStatsMap()
while (std::getline(meminfo, line))
{
LL_DEBUGS("LLMemoryInfo") << line << LL_ENDL;
if (regex_match_no_exc(line, matched, stat_rx))
if (ll_regex_match(line, matched, stat_rx))
{
// e.g. "MemTotal: 4108424 kB"
LLSD::String key(matched[1].first, matched[1].second);

View File

@ -27,7 +27,6 @@
#ifndef LL_LLTHREAD_H
#define LL_LLTHREAD_H
#include "llapp.h"
#include "llapr.h"
#include "boost/intrusive_ptr.hpp"
#include "llrefcount.h"

View File

@ -580,6 +580,31 @@ namespace LLTrace
return typename RelatedTypes<T>::fractional_t(getPeriodMeanPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
}
template <typename T>
typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMedianPerSec(const StatType<T>& stat, S32 num_periods = S32_MAX)
{
num_periods = llmin(num_periods, getNumRecordedPeriods());
std::vector <typename RelatedTypes<typename T::value_t>::fractional_t> buf;
for (S32 i = 1; i <= num_periods; i++)
{
Recording& recording = getPrevRecording(i);
if (recording.getDuration() > (F32Seconds)0.f)
{
buf.push_back(recording.getPerSec(stat));
}
}
std::sort(buf.begin(), buf.end());
return typename RelatedTypes<T>::fractional_t((buf.size() % 2 == 0) ? (buf[buf.size() / 2 - 1] + buf[buf.size() / 2]) / 2 : buf[buf.size() / 2]);
}
template<typename T>
typename RelatedTypes<T>::fractional_t getPeriodMedianPerSec(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
{
return typename RelatedTypes<T>::fractional_t(getPeriodMedianPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
}
//
// PERIODIC STANDARD DEVIATION
//

View File

@ -33,6 +33,7 @@
#include <iphlpapi.h>
#endif
#include "llapp.h"
#include "lldefs.h"
#include "llerror.h"
@ -44,7 +45,7 @@
#include "lltimer.h"
#include "llthread.h"
#include "llmutex.h"
#include "fstelemetry.h"
const LLUUID LLUUID::null;
const LLTransactionID LLTransactionID::tnull;
@ -155,6 +156,7 @@ U32 janky_fast_random_seeded_bytes(U32 seed, U32 val)
// Common to all UUID implementations
void LLUUID::toString(std::string& out) const
{
FSZone;
out = llformat(
"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
(U8)(mData[0]),
@ -217,6 +219,7 @@ BOOL LLUUID::set(const char* in_string, BOOL emit)
BOOL LLUUID::set(const std::string& in_string, BOOL emit)
{
FSZone;
BOOL broken_format = FALSE;
// empty strings should make NULL uuid
@ -1027,6 +1030,7 @@ LLUUID::LLUUID()
// Copy constructor
LLUUID::LLUUID(const LLUUID& rhs)
{
FSZone;
// <FS> Fix for misaligned unsigned ints in LLUUID; by Sovereign Engineer / Shyotl Kuhr
//U32 *tmp = (U32 *)mData;
//U32 *rhstmp = (U32 *)rhs.mData;
@ -1045,6 +1049,7 @@ LLUUID::LLUUID()
// Assignment
LLUUID& LLUUID::operator=(const LLUUID& rhs)
{
FSZone;
// <FS> Fix for misaligned unsigned ints in LLUUID; by Sovereign Engineer / Shyotl Kuhr
//// No need to check the case where this==&rhs. The branch is slower than the write.
//U32 *tmp = (U32 *)mData;

View File

@ -29,10 +29,11 @@
#include <iostream>
#include <set>
#include <vector>
#include <cstring> // <FS:Beq> for std::memmove
#include "stdtypes.h"
#include "llpreprocessor.h"
#include <boost/functional/hash.hpp>
#include "fstelemetry.h"
class LLMutex;
const S32 UUID_BYTES = 16;
@ -56,7 +57,9 @@ public:
explicit LLUUID(const char *in_string); // Convert from string.
explicit LLUUID(const std::string& in_string); // Convert from string.
LLUUID(const LLUUID &in);
LLUUID(LLUUID&& rhs) noexcept { FSZone; std::memmove(mData, rhs.mData, sizeof(mData));};
LLUUID &operator=(const LLUUID &rhs);
LLUUID &operator=(LLUUID &&rhs) noexcept {FSZone; std::memmove(mData, rhs.mData, sizeof(mData));return *this;};
~LLUUID();
@ -112,6 +115,61 @@ public:
void toString(std::string& out) const;
void toCompressedString(char *out) const; // Does not allocate memory, needs 17 characters (including \0)
void toCompressedString(std::string& out) const;
// last 4 chars for quick ref - Very lightweight, no nul-term added - provide your own, ensure min 4 bytes.
# define hexnybl(N) (N)>9?((N)-10)+'a':(N)+'0'
inline char * toShortString(char *out) const
{
FSZone;
out[0] = hexnybl(mData[14]>>4);
out[1] = hexnybl(mData[14]&15);
out[2] = hexnybl(mData[15]>>4);
out[3] = hexnybl(mData[15]&15);
return out;
}
// full uuid - Much lighterweight than default, no allocation, or nul-term added - provide your own, ensure min 36 bytes.
inline char * toStringFast(char *out) const
{
FSZone;
out[0] = hexnybl(mData[0]>>4);
out[1] = hexnybl(mData[0]&15);
out[2] = hexnybl(mData[1]>>4);
out[3] = hexnybl(mData[1]&15);
out[4] = hexnybl(mData[2]>>4);
out[5] = hexnybl(mData[2]&15);
out[6] = hexnybl(mData[3]>>4);
out[7] = hexnybl(mData[3]&15);
out[8] = '-';
out[9] = hexnybl(mData[4]>>4);
out[10] = hexnybl(mData[4]&15);
out[11] = hexnybl(mData[5]>>4);
out[12] = hexnybl(mData[5]&15);
out[13] = '-';
out[14] = hexnybl(mData[6]>>4);
out[15] = hexnybl(mData[6]&15);
out[16] = hexnybl(mData[7]>>4);
out[17] = hexnybl(mData[7]&15);
out[18] = '-';
out[19] = hexnybl(mData[8]>>4);
out[20] = hexnybl(mData[8]&15);
out[21] = hexnybl(mData[9]>>4);
out[22] = hexnybl(mData[9]&15);
out[23] = '-';
out[24] = hexnybl(mData[10]>>4);
out[25] = hexnybl(mData[10]&15);
out[26] = hexnybl(mData[11]>>4);
out[27] = hexnybl(mData[11]&15);
out[28] = hexnybl(mData[12]>>4);
out[29] = hexnybl(mData[12]&15);
out[30] = hexnybl(mData[13]>>4);
out[31] = hexnybl(mData[13]&15);
out[32] = hexnybl(mData[14]>>4);
out[33] = hexnybl(mData[14]&15);
out[34] = hexnybl(mData[15]>>4);
out[35] = hexnybl(mData[15]&15);
return out;
}
std::string asString() const;
std::string getString() const;

View File

@ -181,7 +181,6 @@ if (DARWIN)
set(copy_dylibs
libapr-1.0.dylib
libaprutil-1.0.dylib
libexception_handler.dylib
libnghttp2*.dylib
liburiparser*.dylib
${EXPAT_COPY}

View File

@ -35,6 +35,7 @@
#include "apr.h" // thread-related functions
#include "_refcounted.h"
#include "fstelemetry.h"
namespace LLCoreInt
{
@ -54,6 +55,10 @@ private:
void run()
{ // THREAD CONTEXT
// <FS:Beq> - Add threadnames
LL_INFOS("THREAD") << "Started unnamed HTTP thread " << LL_ENDL;
FSThreadName( "HTTP" );
// </FS:Beq>
// Take out additional reference for the at_exit handler
addRef();

View File

@ -23,13 +23,6 @@
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#if LL_WINDOWS
#define SAFE_SSL 1
#elif LL_DARWIN
#define SAFE_SSL 1
#else
#define SAFE_SSL 1
#endif
#include "linden_common.h" // Modifies curl/curl.h interfaces
#include "httpcommon.h"
@ -38,10 +31,6 @@
#include <curl/curl.h>
#include <string>
#include <sstream>
#if SAFE_SSL
#include <openssl/crypto.h>
#include <functional> // std::hash
#endif
namespace LLCore
@ -281,9 +270,6 @@ namespace LLHttp
{
namespace
{
typedef boost::shared_ptr<LLMutex> LLMutex_ptr;
std::vector<LLMutex_ptr> sSSLMutex;
CURL *getCurlTemplateHandle()
{
static CURL *curlpTemplateHandle = NULL;
@ -348,34 +334,6 @@ void deallocateEasyCurl(CURL *curlp)
}
#if SAFE_SSL
//static
void ssl_locking_callback(int mode, int type, const char *file, int line)
{
if (type >= sSSLMutex.size())
{
LL_WARNS() << "Attempt to get unknown MUTEX in SSL Lock." << LL_ENDL;
}
if (mode & CRYPTO_LOCK)
{
sSSLMutex[type]->lock();
}
else
{
sSSLMutex[type]->unlock();
}
}
//static
unsigned long ssl_thread_id(void)
{
// std::thread::id is very deliberately opaque, but we can hash it
return std::hash<LLThread::id_t>()(LLThread::currentID());
}
#endif
}
void initialize()
@ -387,27 +345,11 @@ void initialize()
check_curl_code(code, CURL_GLOBAL_ALL);
#if SAFE_SSL
S32 mutex_count = CRYPTO_num_locks();
for (S32 i = 0; i < mutex_count; i++)
{
sSSLMutex.push_back(LLMutex_ptr(new LLMutex()));
}
CRYPTO_set_id_callback(&ssl_thread_id);
CRYPTO_set_locking_callback(&ssl_locking_callback);
#endif
}
void cleanup()
{
#if SAFE_SSL
CRYPTO_set_id_callback(NULL);
CRYPTO_set_locking_callback(NULL);
sSSLMutex.clear();
#endif
curl_global_cleanup();
}

View File

@ -726,7 +726,7 @@ bool LLCrashLogger::init()
#if LL_WINDOWS
Sleep(1000);
#else
sleep(1);
::sleep(1);
#endif
locked = mKeyMaster.checkMaster();
}
@ -785,7 +785,7 @@ void LLCrashLogger::init_curl()
}
CRYPTO_set_locking_callback(ssl_locking_callback);
CRYPTO_THREADID_set_callback(ssl_thread_id_callback);
(void)CRYPTO_THREADID_set_callback(ssl_thread_id_callback);
}
}

View File

@ -343,6 +343,11 @@ const std::string &LLDir::getDumpDir() const
return LLDir::sDumpDir;
}
bool LLDir::dumpDirExists() const
{
return !sDumpDir.empty();
}
const std::string &LLDir::getPerAccountChatLogsDir() const
{
return mPerAccountChatLogsDir;
@ -953,6 +958,11 @@ std::string LLDir::getScrubbedFileName(const std::string uncleanFileName)
return name;
}
std::string LLDir::getDumpLogsDirPath(const std::string &file_name)
{
return gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "dump_logs", file_name);
}
// static
std::string LLDir::getForbiddenFileChars()
{

View File

@ -128,6 +128,7 @@ class LLDir
const std::string &getLindenUserDir() const; // Location of the Linden user dir.
const std::string &getChatLogsDir() const; // Location of the chat logs dir.
const std::string &getDumpDir() const; // Location of the per-run dump dir.
bool dumpDirExists() const;
const std::string &getPerAccountChatLogsDir() const; // Location of the per account chat logs dir.
const std::string &getTempDir() const; // Common temporary directory
const std::string getCacheDir(bool get_default = false) const; // Location of the cache.
@ -218,6 +219,8 @@ class LLDir
// random filename in common temporary directory
std::string getTempFilename() const;
static std::string getDumpLogsDirPath(const std::string &file_name = "");
// For producing safe download file names from potentially unsafe ones
static std::string getScrubbedFileName(const std::string uncleanFileName);
static std::string getForbiddenFileChars();

View File

@ -27,8 +27,8 @@
#include "lldiriterator.h"
#include "fix_macros.h"
#include "llregex.h"
#include <boost/filesystem.hpp>
#include <boost/regex.hpp>
namespace fs = boost::filesystem;
@ -131,7 +131,7 @@ bool LLDirIterator::Impl::next(std::string &fname)
{
boost::smatch match;
std::string name = mIter->path().filename().string();
found = boost::regex_match(name, match, mFilterExp);
found = ll_regex_match(name, match, mFilterExp);
if (found)
{
fname = name;

View File

@ -31,6 +31,7 @@
*/
#include "linden_common.h"
#include "llapp.h"
#include "llassettype.h"
#include "lldir.h"
#include <boost/filesystem.hpp>
@ -43,8 +44,6 @@
static const char* subdirs = "0123456789abcdef";
LLDiskCache::LLDiskCache(const std::string cache_dir,
// <FS:Ansariel> Fix integer overflow
//const int max_size_bytes,
const uintmax_t max_size_bytes,
const bool enable_cache_debug_info) :
mCacheDir(cache_dir),
@ -69,6 +68,34 @@ LLDiskCache::LLDiskCache(const std::string cache_dir,
// </FS:Beq>
}
// WARNING: purge() is called by LLPurgeDiskCacheThread. As such it must
// NOT touch any LLDiskCache data without introducing and locking a mutex!
// Interaction through the filesystem itself should be safe. Lets say thread
// A is accessing the cache file for reading/writing and thread B is trimming
// the cache. Lets also assume using llifstream to open a file and
// boost::filesystem::remove are not atomic (which will be pretty much the
// case).
// Now, A is trying to open the file using llifstream ctor. It does some
// checks if the file exists and whatever else it might be doing, but has not
// issued the call to the OS to actually open the file yet. Now B tries to
// delete the file: If the file has been already marked as in use by the OS,
// deleting the file will fail and B will continue with the next file. A can
// safely continue opening the file. If the file has not yet been marked as in
// use, B will delete the file. Now A actually wants to open it, operation
// will fail, subsequent check via llifstream.is_open will fail, asset will
// have to be re-requested. (Assuming here the viewer will actually handle
// this situation properly, that can also happen if there is a file containing
// garbage.)
// Other situation: B is trimming the cache and A wants to read a file that is
// about to get deleted. boost::filesystem::remove does whatever it is doing
// before actually deleting the file. If A opens the file before the file is
// actually gone, the OS call from B to delete the file will fail since the OS
// will prevent this. B continues with the next file. If the file is already
// gone before A finally gets to open it, this operation will fail and the
// asset will have to be re-requested.
void LLDiskCache::purge()
{
if (mEnableCacheDebugInfo)
@ -151,15 +178,12 @@ void LLDiskCache::purge()
{
del++; // Extra accounting to track the retention of static assets
// </FS:Beq>
// <FS:Ansariel> Do not crash if we cannot delete the file for some reason
//boost::filesystem::remove(entry.second.second);
boost::filesystem::remove(entry.second.second, ec);
if (ec.failed())
{
LL_WARNS() << "Failed to delete cache file " << entry.second.second << ": " << ec.message() << LL_ENDL;
}
}
// </FS:Ansariel>
}
else
{
@ -431,8 +455,6 @@ void LLDiskCache::clearCache()
{
if (remove_entry.string().find(mCacheFilenamePrefix) != std::string::npos)
{
// <FS:Ansariel> Do not crash if we cannot delete the file for some reason
//boost::filesystem::remove(entry);
const boost::filesystem::path remove_path = remove_entry;
++entry;
boost::filesystem::remove(remove_path, ec);
@ -440,7 +462,6 @@ void LLDiskCache::clearCache()
{
LL_WARNS() << "Failed to delete cache file " << remove_path.string() << ": " << ec.message() << LL_ENDL;
}
// </FS:Ansariel>
}
else
{
@ -502,26 +523,17 @@ uintmax_t LLDiskCache::dirFileSize(const std::string dir)
return total_file_size;
}
// <FS:Ansariel> Regular disk cache cleanup
FSPurgeDiskCacheThread::FSPurgeDiskCacheThread() :
LLPurgeDiskCacheThread::LLPurgeDiskCacheThread() :
LLThread("PurgeDiskCacheThread", nullptr)
{
}
void FSPurgeDiskCacheThread::run()
void LLPurgeDiskCacheThread::run()
{
constexpr F64 CHECK_INTERVAL = 60;
mTimer.setTimerExpirySec(CHECK_INTERVAL);
mTimer.start();
constexpr std::chrono::seconds CHECK_INTERVAL{60};
do
while (LLApp::instance()->sleep(CHECK_INTERVAL))
{
if (mTimer.checkExpirationAndReset(CHECK_INTERVAL))
{
LLDiskCache::instance().purge();
}
ms_sleep(100);
} while (!isQuitting());
LLDiskCache::instance().purge();
}
}
// </FS:Ansariel>

View File

@ -86,8 +86,6 @@ class LLDiskCache :
* The maximum size of the cache in bytes - Based on the
* setting at 'CacheSize' and 'DiskCachePercentOfTotal'
*/
// <FS:Ansariel> Fix integer overflow
//const int max_size_bytes,
const uintmax_t max_size_bytes,
/**
* A flag that enables extra cache debugging so that
@ -128,6 +126,13 @@ class LLDiskCache :
/**
* Purge the oldest items in the cache so that the combined size of all files
* is no bigger than mMaxSizeBytes.
*
* WARNING: purge() is called by LLPurgeDiskCacheThread. As such it must
* NOT touch any LLDiskCache data without introducing and locking a mutex!
*
* Purging the disk cache involves nontrivial work on the viewer's
* filesystem. If called on the main thread, this causes a noticeable
* freeze.
*/
void purge();
@ -200,17 +205,12 @@ class LLDiskCache :
std::vector<std::string> mSkipList; // <FS:Beq/> Vector of "static" untouchable assets that should never be purged
};
// <FS:Ansariel> Regular disk cache cleanup
class FSPurgeDiskCacheThread : public LLThread
class LLPurgeDiskCacheThread : public LLThread
{
public:
FSPurgeDiskCacheThread();
LLPurgeDiskCacheThread();
protected:
void run() override;
private:
LLTimer mTimer;
};
// </FS:Ansariel>
#endif // _LLDISKCACHE

View File

@ -48,6 +48,28 @@ LLFileSystem::LLFileSystem(const LLUUID& file_id, const LLAssetType::EType file_
mPosition = 0;
mBytesRead = 0;
mMode = mode;
// This block of code was originally called in the read() method but after comments here:
// https://bitbucket.org/lindenlab/viewer/commits/e28c1b46e9944f0215a13cab8ee7dded88d7fc90#comment-10537114
// we decided to follow Henri's suggestion and move the code to update the last access time here.
if (mode == LLFileSystem::READ)
{
// build the filename (TODO: we do this in a few places - perhaps we should factor into a single function)
std::string id;
mFileID.toString(id);
const std::string extra_info = "";
const std::string filename = LLDiskCache::getInstance()->metaDataToFilepath(id, mFileType, extra_info);
// update the last access time for the file if it exists - this is required
// even though we are reading and not writing because this is the
// way the cache works - it relies on a valid "last accessed time" for
// each file so it knows how to remove the oldest, unused files
bool exists = gDirUtilp->fileExists(filename);
if (exists)
{
LLDiskCache::getInstance()->updateFileAccessTime(filename);
}
}
}
LLFileSystem::~LLFileSystem()
@ -153,8 +175,6 @@ S32 LLFileSystem::getFileSize(const LLUUID& file_id, const LLAssetType::EType fi
BOOL LLFileSystem::read(U8* buffer, S32 bytes)
{
FSZoneC(tracy::Color::Gold); // <FS:Beq> measure cache performance
// <FS:Ansariel> Cache fixes
//BOOL success = TRUE;
BOOL success = FALSE;
std::string id;
@ -182,9 +202,9 @@ BOOL LLFileSystem::read(U8* buffer, S32 bytes)
// file.close();
// mPosition += mBytesRead;
// if (!mBytesRead)
// if (mBytesRead)
// {
// success = FALSE;
// success = TRUE;
// }
//}
LLFILE* file = LLFile::fopen(filename, "rb");
@ -206,12 +226,6 @@ BOOL LLFileSystem::read(U8* buffer, S32 bytes)
}
// </FS:Ansariel>
// update the last access time for the file - this is required
// even though we are reading and not writing because this is the
// way the cache works - it relies on a valid "last accessed time" for
// each file so it knows how to remove the oldest, unused files
LLDiskCache::getInstance()->updateFileAccessTime(filename);
return success;
}

View File

@ -1498,7 +1498,7 @@ bool LLImageRaw::scale( S32 new_width, S32 new_height, bool scale_image_data )
setDataAndSize(new_data, new_width, new_height, components);
}
}
else
else try
{
// copy out existing image data
S32 temp_data_size = old_width * old_height * components;
@ -1532,6 +1532,11 @@ bool LLImageRaw::scale( S32 new_width, S32 new_height, bool scale_image_data )
}
}
}
catch (std::bad_alloc&) // for temp_buffer
{
LL_WARNS() << "Failed to allocate temporary image buffer" << LL_ENDL;
return false;
}
return true ;
}

View File

@ -395,7 +395,7 @@ bool LLSettingsBase::validate()
LLSD LLSettingsBase::settingValidation(LLSD &settings, validation_list_t &validations, bool partial)
{
static Validator validateName(SETTING_NAME, false, LLSD::TypeString, boost::bind(&Validator::verifyStringLength, _1, 63));
static Validator validateName(SETTING_NAME, false, LLSD::TypeString, boost::bind(&Validator::verifyStringLength, _1, _2, 63));
static Validator validateId(SETTING_ID, false, LLSD::TypeUUID);
static Validator validateHash(SETTING_HASH, false, LLSD::TypeInteger);
static Validator validateType(SETTING_TYPE, false, LLSD::TypeString);
@ -534,7 +534,7 @@ bool LLSettingsBase::Validator::verify(LLSD &data, U32 flags)
return false;
}
if (!mVerify.empty() && !mVerify(data[mName]))
if (!mVerify.empty() && !mVerify(data[mName], flags))
{
LL_WARNS("SETTINGS") << "Setting '" << mName << "' fails validation." << LL_ENDL;
return false;
@ -543,17 +543,17 @@ bool LLSettingsBase::Validator::verify(LLSD &data, U32 flags)
return true;
}
bool LLSettingsBase::Validator::verifyColor(LLSD &value)
bool LLSettingsBase::Validator::verifyColor(LLSD &value, U32)
{
return (value.size() == 3 || value.size() == 4);
}
bool LLSettingsBase::Validator::verifyVector(LLSD &value, S32 length)
bool LLSettingsBase::Validator::verifyVector(LLSD &value, U32, S32 length)
{
return (value.size() == length);
}
bool LLSettingsBase::Validator::verifyVectorNormalized(LLSD &value, S32 length)
bool LLSettingsBase::Validator::verifyVectorNormalized(LLSD &value, U32, S32 length)
{
if (value.size() != length)
return false;
@ -596,7 +596,7 @@ bool LLSettingsBase::Validator::verifyVectorNormalized(LLSD &value, S32 length)
return true;
}
bool LLSettingsBase::Validator::verifyVectorMinMax(LLSD &value, LLSD minvals, LLSD maxvals)
bool LLSettingsBase::Validator::verifyVectorMinMax(LLSD &value, U32, LLSD minvals, LLSD maxvals)
{
for (S32 index = 0; index < value.size(); ++index)
{
@ -619,12 +619,12 @@ bool LLSettingsBase::Validator::verifyVectorMinMax(LLSD &value, LLSD minvals, LL
return true;
}
bool LLSettingsBase::Validator::verifyQuaternion(LLSD &value)
bool LLSettingsBase::Validator::verifyQuaternion(LLSD &value, U32)
{
return (value.size() == 4);
}
bool LLSettingsBase::Validator::verifyQuaternionNormal(LLSD &value)
bool LLSettingsBase::Validator::verifyQuaternionNormal(LLSD &value, U32)
{
if (value.size() != 4)
return false;
@ -642,7 +642,7 @@ bool LLSettingsBase::Validator::verifyQuaternionNormal(LLSD &value)
return true;
}
bool LLSettingsBase::Validator::verifyFloatRange(LLSD &value, LLSD range)
bool LLSettingsBase::Validator::verifyFloatRange(LLSD &value, U32, LLSD range)
{
F64 real = value.asReal();
@ -655,7 +655,7 @@ bool LLSettingsBase::Validator::verifyFloatRange(LLSD &value, LLSD range)
return true;
}
bool LLSettingsBase::Validator::verifyIntegerRange(LLSD &value, LLSD range)
bool LLSettingsBase::Validator::verifyIntegerRange(LLSD &value, U32, LLSD range)
{
S32 ival = value.asInteger();
@ -668,7 +668,7 @@ bool LLSettingsBase::Validator::verifyIntegerRange(LLSD &value, LLSD range)
return true;
}
bool LLSettingsBase::Validator::verifyStringLength(LLSD &value, S32 length)
bool LLSettingsBase::Validator::verifyStringLength(LLSD &value, U32, S32 length)
{
std::string sval = value.asString();

View File

@ -270,7 +270,7 @@ public:
public:
static const U32 VALIDATION_PARTIAL;
typedef boost::function<bool(LLSD &)> verify_pr;
typedef boost::function<bool(LLSD &, U32)> verify_pr;
Validator(std::string name, bool required, LLSD::Type type, verify_pr verify = verify_pr(), LLSD defval = LLSD()) :
mName(name),
@ -287,15 +287,15 @@ public:
bool verify(LLSD &data, U32 flags);
// Some basic verifications
static bool verifyColor(LLSD &value);
static bool verifyVector(LLSD &value, S32 length);
static bool verifyVectorMinMax(LLSD &value, LLSD minvals, LLSD maxvals);
static bool verifyVectorNormalized(LLSD &value, S32 length);
static bool verifyQuaternion(LLSD &value);
static bool verifyQuaternionNormal(LLSD &value);
static bool verifyFloatRange(LLSD &value, LLSD range);
static bool verifyIntegerRange(LLSD &value, LLSD range);
static bool verifyStringLength(LLSD &value, S32 length);
static bool verifyColor(LLSD &value, U32 flags);
static bool verifyVector(LLSD &value, U32 flags, S32 length);
static bool verifyVectorMinMax(LLSD &value, U32 flags, LLSD minvals, LLSD maxvals);
static bool verifyVectorNormalized(LLSD &value, U32 flags, S32 length);
static bool verifyQuaternion(LLSD &value, U32 flags);
static bool verifyQuaternionNormal(LLSD &value, U32 flags);
static bool verifyFloatRange(LLSD &value, U32 flags, LLSD range);
static bool verifyIntegerRange(LLSD &value, U32 flags, LLSD range);
static bool verifyStringLength(LLSD &value, U32 flags, S32 length);
private:
std::string mName;

View File

@ -461,7 +461,7 @@ void LLSettingsDay::blend(const LLSettingsBase::ptr_t &other, F64 mix)
namespace
{
bool validateDayCycleTrack(LLSD &value)
bool validateDayCycleTrack(LLSD &value, U32 flags)
{
// Trim extra tracks.
while (value.size() > LLSettingsDay::TRACK_MAX)
@ -532,7 +532,7 @@ namespace
return true;
}
bool validateDayCycleFrames(LLSD &value)
bool validateDayCycleFrames(LLSD &value, U32 flags)
{
bool hasSky(false);
bool hasWater(false);
@ -545,7 +545,7 @@ namespace
if (ftype == "sky")
{
LLSettingsSky::validation_list_t valid_sky = LLSettingsSky::validationList();
LLSD res_sky = LLSettingsBase::settingValidation(frame, valid_sky);
LLSD res_sky = LLSettingsBase::settingValidation(frame, valid_sky, flags);
if (res_sky["success"].asInteger() == 0)
{
@ -558,7 +558,7 @@ namespace
else if (ftype == "water")
{
LLSettingsWater::validation_list_t valid_h2o = LLSettingsWater::validationList();
LLSD res_h2o = LLSettingsBase::settingValidation(frame, valid_h2o);
LLSD res_h2o = LLSettingsBase::settingValidation(frame, valid_h2o, flags);
if (res_h2o["success"].asInteger() == 0)
{
LL_WARNS("SETTINGS") << "Water setting named '" << (*itf).first << "' validation failed!: " << res_h2o << LL_ENDL;
@ -574,18 +574,20 @@ namespace
}
}
if (!hasSky)
if ((flags & LLSettingsBase::Validator::VALIDATION_PARTIAL) == 0)
{
LL_WARNS("SETTINGS") << "No skies defined." << LL_ENDL;
return false;
}
if (!hasSky)
{
LL_WARNS("SETTINGS") << "No skies defined." << LL_ENDL;
return false;
}
if (!hasWater)
{
LL_WARNS("SETTINGS") << "No waters defined." << LL_ENDL;
return false;
if (!hasWater)
{
LL_WARNS("SETTINGS") << "No waters defined." << LL_ENDL;
return false;
}
}
return true;
}
}

View File

@ -156,29 +156,29 @@ LLSettingsSky::validation_list_t legacyHazeValidationList()
if (legacyHazeValidation.empty())
{
legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_AMBIENT, false, LLSD::TypeArray,
boost::bind(&LLSettingsBase::Validator::verifyVectorMinMax, _1,
boost::bind(&LLSettingsBase::Validator::verifyVectorMinMax, _1, _2,
LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")),
LLSD(LLSDArray(3.0f)(3.0f)(3.0f)("*")))));
legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_BLUE_DENSITY, false, LLSD::TypeArray,
boost::bind(&LLSettingsBase::Validator::verifyVectorMinMax, _1,
boost::bind(&LLSettingsBase::Validator::verifyVectorMinMax, _1, _2,
LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")),
LLSD(LLSDArray(3.0f)(3.0f)(3.0f)("*")))));
legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_BLUE_HORIZON, false, LLSD::TypeArray,
boost::bind(&LLSettingsBase::Validator::verifyVectorMinMax, _1,
boost::bind(&LLSettingsBase::Validator::verifyVectorMinMax, _1, _2,
LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")),
LLSD(LLSDArray(3.0f)(3.0f)(3.0f)("*")))));
legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_HAZE_DENSITY, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(5.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(5.0f)))));
legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_HAZE_HORIZON, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(5.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(5.0f)))));
// <FS:Beq> FIRE-29682 Allow full range density multipliers
// legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_MULTIPLIER, false, LLSD::TypeReal,
// boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0001f)(2.0f)))));
// boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0001f)(2.0f)))));
legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_MULTIPLIER, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0000001f)(2.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0000001f)(2.0f)))));
// </FS:Beq>
legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DISTANCE_MULTIPLIER, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0001f)(1000.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0001f)(1000.0f)))));
}
return legacyHazeValidation;
}
@ -189,19 +189,19 @@ LLSettingsSky::validation_list_t rayleighValidationList()
if (rayleighValidation.empty())
{
rayleighValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_WIDTH, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(32768.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(32768.0f)))));
rayleighValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_TERM, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(2.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(2.0f)))));
rayleighValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(-1.0f)(1.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(-1.0f)(1.0f)))));
rayleighValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_LINEAR_TERM, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(2.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(2.0f)))));
rayleighValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_CONSTANT_TERM, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(1.0f)))));
}
return rayleighValidation;
}
@ -212,19 +212,19 @@ LLSettingsSky::validation_list_t absorptionValidationList()
if (absorptionValidation.empty())
{
absorptionValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_WIDTH, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(32768.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(32768.0f)))));
absorptionValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_TERM, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(2.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(2.0f)))));
absorptionValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(-1.0f)(1.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(-1.0f)(1.0f)))));
absorptionValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_LINEAR_TERM, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(2.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(2.0f)))));
absorptionValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_CONSTANT_TERM, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(1.0f)))));
}
return absorptionValidation;
}
@ -235,31 +235,31 @@ LLSettingsSky::validation_list_t mieValidationList()
if (mieValidation.empty())
{
mieValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_WIDTH, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(32768.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(32768.0f)))));
mieValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_TERM, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(2.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(2.0f)))));
mieValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(-1.0f)(1.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(-1.0f)(1.0f)))));
mieValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_LINEAR_TERM, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(2.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(2.0f)))));
mieValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_CONSTANT_TERM, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(1.0f)))));
mieValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_MIE_ANISOTROPY_FACTOR, false, LLSD::TypeReal,
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f)))));
boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(1.0f)))));
}
return mieValidation;
}
bool validateLegacyHaze(LLSD &value)
bool validateLegacyHaze(LLSD &value, U32 flags)
{
LLSettingsSky::validation_list_t legacyHazeValidations = legacyHazeValidationList();
llassert(value.type() == LLSD::TypeMap);
LLSD result = LLSettingsBase::settingValidation(value, legacyHazeValidations);
LLSD result = LLSettingsBase::settingValidation(value, legacyHazeValidations, flags);
if (result["errors"].size() > 0)
{
LL_WARNS("SETTINGS") << "Legacy Haze Config Validation errors: " << result["errors"] << LL_ENDL;
@ -273,7 +273,7 @@ bool validateLegacyHaze(LLSD &value)
return true;
}
bool validateRayleighLayers(LLSD &value)
bool validateRayleighLayers(LLSD &value, U32 flags)
{
LLSettingsSky::validation_list_t rayleighValidations = rayleighValidationList();
if (value.isArray())
@ -284,24 +284,24 @@ bool validateRayleighLayers(LLSD &value)
LLSD& layerConfig = (*itf);
if (layerConfig.type() == LLSD::TypeMap)
{
if (!validateRayleighLayers(layerConfig))
if (!validateRayleighLayers(layerConfig, flags))
{
allGood = false;
}
}
else if (layerConfig.type() == LLSD::TypeArray)
{
return validateRayleighLayers(layerConfig);
return validateRayleighLayers(layerConfig, flags);
}
else
{
return LLSettingsBase::settingValidation(value, rayleighValidations);
return LLSettingsBase::settingValidation(value, rayleighValidations, flags);
}
}
return allGood;
}
llassert(value.type() == LLSD::TypeMap);
LLSD result = LLSettingsBase::settingValidation(value, rayleighValidations);
LLSD result = LLSettingsBase::settingValidation(value, rayleighValidations, flags);
if (result["errors"].size() > 0)
{
LL_WARNS("SETTINGS") << "Rayleigh Config Validation errors: " << result["errors"] << LL_ENDL;
@ -315,7 +315,7 @@ bool validateRayleighLayers(LLSD &value)
return true;
}
bool validateAbsorptionLayers(LLSD &value)
bool validateAbsorptionLayers(LLSD &value, U32 flags)
{
LLSettingsBase::validation_list_t absorptionValidations = absorptionValidationList();
if (value.isArray())
@ -326,24 +326,24 @@ bool validateAbsorptionLayers(LLSD &value)
LLSD& layerConfig = (*itf);
if (layerConfig.type() == LLSD::TypeMap)
{
if (!validateAbsorptionLayers(layerConfig))
if (!validateAbsorptionLayers(layerConfig, flags))
{
allGood = false;
}
}
else if (layerConfig.type() == LLSD::TypeArray)
{
return validateAbsorptionLayers(layerConfig);
return validateAbsorptionLayers(layerConfig, flags);
}
else
{
return LLSettingsBase::settingValidation(value, absorptionValidations);
return LLSettingsBase::settingValidation(value, absorptionValidations, flags);
}
}
return allGood;
}
llassert(value.type() == LLSD::TypeMap);
LLSD result = LLSettingsBase::settingValidation(value, absorptionValidations);
LLSD result = LLSettingsBase::settingValidation(value, absorptionValidations, flags);
if (result["errors"].size() > 0)
{
LL_WARNS("SETTINGS") << "Absorption Config Validation errors: " << result["errors"] << LL_ENDL;
@ -357,7 +357,7 @@ bool validateAbsorptionLayers(LLSD &value)
return true;
}
bool validateMieLayers(LLSD &value)
bool validateMieLayers(LLSD &value, U32 flags)
{
LLSettingsBase::validation_list_t mieValidations = mieValidationList();
if (value.isArray())
@ -368,23 +368,23 @@ bool validateMieLayers(LLSD &value)
LLSD& layerConfig = (*itf);
if (layerConfig.type() == LLSD::TypeMap)
{
if (!validateMieLayers(layerConfig))
if (!validateMieLayers(layerConfig, flags))
{
allGood = false;
}
}
else if (layerConfig.type() == LLSD::TypeArray)
{
return validateMieLayers(layerConfig);
return validateMieLayers(layerConfig, flags);
}
else
{
return LLSettingsBase::settingValidation(value, mieValidations);
return LLSettingsBase::settingValidation(value, mieValidations, flags);
}
}
return allGood;
}
LLSD result = LLSettingsBase::settingValidation(value, mieValidations);
LLSD result = LLSettingsBase::settingValidation(value, mieValidations, flags);
if (result["errors"].size() > 0)
{
LL_WARNS("SETTINGS") << "Mie Config Validation errors: " << result["errors"] << LL_ENDL;
@ -563,80 +563,80 @@ LLSettingsSky::validation_list_t LLSettingsSky::validationList()
validation.push_back(Validator(SETTING_HALO_TEXTUREID, false, LLSD::TypeUUID));
validation.push_back(Validator(SETTING_CLOUD_COLOR, true, LLSD::TypeArray,
boost::bind(&Validator::verifyVectorMinMax, _1,
boost::bind(&Validator::verifyVectorMinMax, _1, _2,
LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")),
LLSD(LLSDArray(1.0f)(1.0f)(1.0f)("*")))));
validation.push_back(Validator(SETTING_CLOUD_POS_DENSITY1, true, LLSD::TypeArray,
boost::bind(&Validator::verifyVectorMinMax, _1,
boost::bind(&Validator::verifyVectorMinMax, _1, _2,
LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")),
LLSD(LLSDArray(1.0f)(1.0f)(3.0f)("*")))));
validation.push_back(Validator(SETTING_CLOUD_POS_DENSITY2, true, LLSD::TypeArray,
boost::bind(&Validator::verifyVectorMinMax, _1,
boost::bind(&Validator::verifyVectorMinMax, _1, _2,
LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")),
LLSD(LLSDArray(1.0f)(1.0f)(1.0f)("*")))));
validation.push_back(Validator(SETTING_CLOUD_SCALE, true, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.001f)(3.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.001f)(3.0f)))));
validation.push_back(Validator(SETTING_CLOUD_SCROLL_RATE, true, LLSD::TypeArray,
boost::bind(&Validator::verifyVectorMinMax, _1,
boost::bind(&Validator::verifyVectorMinMax, _1, _2,
LLSD(LLSDArray(-50.0f)(-50.0f)),
LLSD(LLSDArray(50.0f)(50.0f)))));
validation.push_back(Validator(SETTING_CLOUD_SHADOW, true, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(1.0f)))));
validation.push_back(Validator(SETTING_CLOUD_TEXTUREID, false, LLSD::TypeUUID));
validation.push_back(Validator(SETTING_CLOUD_VARIANCE, false, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(1.0f)))));
validation.push_back(Validator(SETTING_DOME_OFFSET, false, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(1.0f)))));
validation.push_back(Validator(SETTING_DOME_RADIUS, false, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(1000.0f)(2000.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(1000.0f)(2000.0f)))));
validation.push_back(Validator(SETTING_GAMMA, true, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(20.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(20.0f)))));
validation.push_back(Validator(SETTING_GLOW, true, LLSD::TypeArray,
boost::bind(&Validator::verifyVectorMinMax, _1,
boost::bind(&Validator::verifyVectorMinMax, _1, _2,
LLSD(LLSDArray(0.2f)("*")(-10.0f)("*")),
LLSD(LLSDArray(40.0f)("*")(10.0f)("*")))));
validation.push_back(Validator(SETTING_MAX_Y, true, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(10000.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(10000.0f)))));
validation.push_back(Validator(SETTING_MOON_ROTATION, true, LLSD::TypeArray, &Validator::verifyQuaternionNormal));
validation.push_back(Validator(SETTING_MOON_SCALE, false, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.25f)(20.0f))), LLSD::Real(1.0)));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.25f)(20.0f))), LLSD::Real(1.0)));
validation.push_back(Validator(SETTING_MOON_TEXTUREID, false, LLSD::TypeUUID));
validation.push_back(Validator(SETTING_MOON_BRIGHTNESS, false, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(1.0f)))));
validation.push_back(Validator(SETTING_STAR_BRIGHTNESS, true, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(500.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(500.0f)))));
validation.push_back(Validator(SETTING_SUNLIGHT_COLOR, true, LLSD::TypeArray,
boost::bind(&Validator::verifyVectorMinMax, _1,
boost::bind(&Validator::verifyVectorMinMax, _1, _2,
LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")),
LLSD(LLSDArray(3.0f)(3.0f)(3.0f)("*")))));
validation.push_back(Validator(SETTING_SUN_ROTATION, true, LLSD::TypeArray, &Validator::verifyQuaternionNormal));
validation.push_back(Validator(SETTING_SUN_SCALE, false, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.25f)(20.0f))), LLSD::Real(1.0)));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.25f)(20.0f))), LLSD::Real(1.0)));
validation.push_back(Validator(SETTING_SUN_TEXTUREID, false, LLSD::TypeUUID));
validation.push_back(Validator(SETTING_PLANET_RADIUS, true, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(1000.0f)(32768.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(1000.0f)(32768.0f)))));
validation.push_back(Validator(SETTING_SKY_BOTTOM_RADIUS, true, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(1000.0f)(32768.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(1000.0f)(32768.0f)))));
validation.push_back(Validator(SETTING_SKY_TOP_RADIUS, true, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(1000.0f)(32768.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(1000.0f)(32768.0f)))));
validation.push_back(Validator(SETTING_SUN_ARC_RADIANS, true, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(0.1f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(0.1f)))));
validation.push_back(Validator(SETTING_SKY_MOISTURE_LEVEL, false, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(1.0f)))));
validation.push_back(Validator(SETTING_SKY_DROPLET_RADIUS, false, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(5.0f)(1000.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(5.0f)(1000.0f)))));
validation.push_back(Validator(SETTING_SKY_ICE_LEVEL, false, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(1.0f)))));
validation.push_back(Validator(SETTING_RAYLEIGH_CONFIG, true, LLSD::TypeArray, &validateRayleighLayers));
validation.push_back(Validator(SETTING_ABSORPTION_CONFIG, true, LLSD::TypeArray, &validateAbsorptionLayers));

View File

@ -236,34 +236,34 @@ LLSettingsWater::validation_list_t LLSettingsWater::validationList()
// in deeply nested arrays like this [[[[[[[[[[v1,v2,v3]]]]]]]]]]
validation.push_back(Validator(SETTING_BLUR_MULTIPLIER, true, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(-0.5f)(0.5f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(-0.5f)(0.5f)))));
validation.push_back(Validator(SETTING_FOG_COLOR, true, LLSD::TypeArray,
boost::bind(&Validator::verifyVectorMinMax, _1,
boost::bind(&Validator::verifyVectorMinMax, _1, _2,
LLSD(LLSDArray(0.0f)(0.0f)(0.0f)(1.0f)),
LLSD(LLSDArray(1.0f)(1.0f)(1.0f)(1.0f)))));
validation.push_back(Validator(SETTING_FOG_DENSITY, true, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(-10.0f)(10.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(-10.0f)(10.0f)))));
validation.push_back(Validator(SETTING_FOG_MOD, true, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(20.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(20.0f)))));
validation.push_back(Validator(SETTING_FRESNEL_OFFSET, true, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(1.0f)))));
validation.push_back(Validator(SETTING_FRESNEL_SCALE, true, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(1.0f)))));
validation.push_back(Validator(SETTING_NORMAL_MAP, true, LLSD::TypeUUID));
validation.push_back(Validator(SETTING_NORMAL_SCALE, true, LLSD::TypeArray,
boost::bind(&Validator::verifyVectorMinMax, _1,
boost::bind(&Validator::verifyVectorMinMax, _1, _2,
LLSD(LLSDArray(0.0f)(0.0f)(0.0f)),
LLSD(LLSDArray(10.0f)(10.0f)(10.0f)))));
validation.push_back(Validator(SETTING_SCALE_ABOVE, true, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(3.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(3.0f)))));
validation.push_back(Validator(SETTING_SCALE_BELOW, true, LLSD::TypeReal,
boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(3.0f)))));
boost::bind(&Validator::verifyFloatRange, _1, _2, LLSD(LLSDArray(0.0f)(3.0f)))));
validation.push_back(Validator(SETTING_WAVE1_DIR, true, LLSD::TypeArray,
boost::bind(&Validator::verifyVectorMinMax, _1,
boost::bind(&Validator::verifyVectorMinMax, _1, _2,
LLSD(LLSDArray(-20.0f)(-20.0f)),
LLSD(LLSDArray(20.0f)(20.0f)))));
validation.push_back(Validator(SETTING_WAVE2_DIR, true, LLSD::TypeArray,
boost::bind(&Validator::verifyVectorMinMax, _1,
boost::bind(&Validator::verifyVectorMinMax, _1, _2,
LLSD(LLSDArray(-20.0f)(-20.0f)),
LLSD(LLSDArray(20.0f)(20.0f)))));
}

View File

@ -52,24 +52,28 @@ U32 LLBlowfishCipher::encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len)
if (src_len > dst_len) return 0;
// OpenSSL uses "cipher contexts" to hold encryption parameters.
EVP_CIPHER_CTX context;
EVP_CIPHER_CTX_init(&context);
EVP_CIPHER_CTX *context = EVP_CIPHER_CTX_new();
if (!context)
{
LL_WARNS() << "LLBlowfishCipher::encrypt EVP_CIPHER_CTX initiation failure" << LL_ENDL;
return 0;
}
// We want a blowfish cyclic block chain cipher, but need to set
// the key length before we pass in a key, so call EncryptInit
// first with NULLs.
EVP_EncryptInit_ex(&context, EVP_bf_cbc(), NULL, NULL, NULL);
EVP_CIPHER_CTX_set_key_length(&context, (int)mSecretSize);
EVP_EncryptInit_ex(context, EVP_bf_cbc(), NULL, NULL, NULL);
EVP_CIPHER_CTX_set_key_length(context, (int)mSecretSize);
// Complete initialization. Per EVP_EncryptInit man page, the
// cipher pointer must be NULL. Apparently initial_vector must
// be 8 bytes for blowfish, as this is the block size.
unsigned char initial_vector[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
EVP_EncryptInit_ex(&context, NULL, NULL, mSecret, initial_vector);
EVP_EncryptInit_ex(context, NULL, NULL, mSecret, initial_vector);
int blocksize = EVP_CIPHER_CTX_block_size(&context);
int keylen = EVP_CIPHER_CTX_key_length(&context);
int iv_length = EVP_CIPHER_CTX_iv_length(&context);
int blocksize = EVP_CIPHER_CTX_block_size(context);
int keylen = EVP_CIPHER_CTX_key_length(context);
int iv_length = EVP_CIPHER_CTX_iv_length(context);
LL_DEBUGS() << "LLBlowfishCipher blocksize " << blocksize
<< " keylen " << keylen
<< " iv_len " << iv_length
@ -77,7 +81,7 @@ U32 LLBlowfishCipher::encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len)
int output_len = 0;
int temp_len = 0;
if (!EVP_EncryptUpdate(&context,
if (!EVP_EncryptUpdate(context,
dst,
&output_len,
src,
@ -89,18 +93,18 @@ U32 LLBlowfishCipher::encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len)
// There may be some final data left to encrypt if the input is
// not an exact multiple of the block size.
if (!EVP_EncryptFinal_ex(&context, (unsigned char*)(dst + output_len), &temp_len))
if (!EVP_EncryptFinal_ex(context, (unsigned char*)(dst + output_len), &temp_len))
{
LL_WARNS() << "LLBlowfishCipher::encrypt EVP_EncryptFinal failure" << LL_ENDL;
goto ERROR;
}
output_len += temp_len;
EVP_CIPHER_CTX_cleanup(&context);
EVP_CIPHER_CTX_free(context);
return output_len;
ERROR:
EVP_CIPHER_CTX_cleanup(&context);
EVP_CIPHER_CTX_free(context);
return 0;
}
@ -113,18 +117,22 @@ U32 LLBlowfishCipher::decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len)
if (!src || !src_len || !dst || !dst_len) return 0;
if (src_len > dst_len) return 0;
EVP_CIPHER_CTX context;
EVP_CIPHER_CTX_init(&context);
EVP_DecryptInit_ex(&context, EVP_bf_cbc(), NULL, NULL, NULL);
EVP_CIPHER_CTX_set_key_length(&context, (int)mSecretSize);
EVP_CIPHER_CTX *context = EVP_CIPHER_CTX_new();
if (!context)
{
LL_WARNS() << "LLBlowfishCipher::encrypt EVP_CIPHER_CTX initiation failure" << LL_ENDL;
return 0;
}
EVP_DecryptInit_ex(context, EVP_bf_cbc(), NULL, NULL, NULL);
EVP_CIPHER_CTX_set_key_length(context, (int)mSecretSize);
unsigned char initial_vector[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
EVP_DecryptInit_ex(&context, NULL, NULL, mSecret, initial_vector);
EVP_DecryptInit_ex(context, NULL, NULL, mSecret, initial_vector);
int blocksize = EVP_CIPHER_CTX_block_size(&context);
int keylen = EVP_CIPHER_CTX_key_length(&context);
int iv_length = EVP_CIPHER_CTX_iv_length(&context);
int blocksize = EVP_CIPHER_CTX_block_size(context);
int keylen = EVP_CIPHER_CTX_key_length(context);
int iv_length = EVP_CIPHER_CTX_iv_length(context);
LL_DEBUGS() << "LLBlowfishCipher blocksize " << blocksize
<< " keylen " << keylen
<< " iv_len " << iv_length
@ -132,12 +140,12 @@ U32 LLBlowfishCipher::decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len)
int out_len = 0;
int tmp_len = 0;
if (!EVP_DecryptUpdate(&context, dst, &out_len, src, src_len))
if (!EVP_DecryptUpdate(context, dst, &out_len, src, src_len))
{
LL_WARNS() << "LLBlowfishCipher::decrypt EVP_DecryptUpdate failure" << LL_ENDL;
goto ERROR;
}
if (!EVP_DecryptFinal_ex(&context, dst + out_len, &tmp_len))
if (!EVP_DecryptFinal_ex(context, dst + out_len, &tmp_len))
{
LL_WARNS() << "LLBlowfishCipher::decrypt EVP_DecryptFinal failure" << LL_ENDL;
goto ERROR;
@ -145,11 +153,11 @@ U32 LLBlowfishCipher::decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len)
out_len += tmp_len;
EVP_CIPHER_CTX_cleanup(&context);
EVP_CIPHER_CTX_free(context);
return out_len;
ERROR:
EVP_CIPHER_CTX_cleanup(&context);
EVP_CIPHER_CTX_free(context);
return 0;
// </FS:CR>
}

View File

@ -172,6 +172,71 @@ BOOL LLDataPacker::unpackFixed(F32 &value, const char *name,
return success;
}
BOOL LLDataPacker::unpackU16s(U16 *values, S32 count, const char *name)
{
for (S32 idx = 0; idx < count; ++idx)
{
if (!unpackU16(values[idx], name))
{
LL_WARNS("DATAPACKER") << "Buffer overflow reading Unsigned 16s \"" << name << "\" at index " << idx << "!" << LL_ENDL;
return FALSE;
}
}
return TRUE;
}
BOOL LLDataPacker::unpackS16s(S16 *values, S32 count, const char *name)
{
for (S32 idx = 0; idx < count; ++idx)
{
if (!unpackS16(values[idx], name))
{
LL_WARNS("DATAPACKER") << "Buffer overflow reading Signed 16s \"" << name << "\" at index " << idx << "!" << LL_ENDL;
return FALSE;
}
}
return TRUE;
}
BOOL LLDataPacker::unpackF32s(F32 *values, S32 count, const char *name)
{
for (S32 idx = 0; idx < count; ++idx)
{
if (!unpackF32(values[idx], name))
{
LL_WARNS("DATAPACKER") << "Buffer overflow reading Float 32s \"" << name << "\" at index " << idx << "!" << LL_ENDL;
return FALSE;
}
}
return TRUE;
}
BOOL LLDataPacker::unpackColor4Us(LLColor4U *values, S32 count, const char *name)
{
for (S32 idx = 0; idx < count; ++idx)
{
if (!unpackColor4U(values[idx], name))
{
LL_WARNS("DATAPACKER") << "Buffer overflow reading Float 32s \"" << name << "\" at index " << idx << "!" << LL_ENDL;
return FALSE;
}
}
return TRUE;
}
BOOL LLDataPacker::unpackUUIDs(LLUUID *values, S32 count, const char *name)
{
for (S32 idx = 0; idx < count; ++idx)
{
if (!unpackUUID(values[idx], name))
{
LL_WARNS("DATAPACKER") << "Buffer overflow reading UUIDs \"" << name << "\" at index " << idx << "!" << LL_ENDL;
return FALSE;
}
}
return TRUE;
}
//---------------------------------------------------------------------------
// LLDataPackerBinaryBuffer implementation
//---------------------------------------------------------------------------
@ -339,6 +404,29 @@ BOOL LLDataPackerBinaryBuffer::unpackU16(U16 &value, const char *name)
return TRUE;
}
BOOL LLDataPackerBinaryBuffer::packS16(const S16 value, const char *name)
{
BOOL success = verifyLength(sizeof(S16), name);
if (mWriteEnabled && success)
{
htolememcpy(mCurBufferp, &value, MVT_S16, 2);
}
mCurBufferp += 2;
return success;
}
BOOL LLDataPackerBinaryBuffer::unpackS16(S16 &value, const char *name)
{
BOOL success = verifyLength(sizeof(S16), name);
if (success)
{
htolememcpy(&value, mCurBufferp, MVT_S16, 2);
}
mCurBufferp += 2;
return success;
}
BOOL LLDataPackerBinaryBuffer::packU32(const U32 value, const char *name)
{
@ -939,6 +1027,52 @@ BOOL LLDataPackerAsciiBuffer::unpackU16(U16 &value, const char *name)
return success;
}
BOOL LLDataPackerAsciiBuffer::packS16(const S16 value, const char *name)
{
BOOL success = TRUE;
writeIndentedName(name);
int numCopied = 0;
if (mWriteEnabled)
{
numCopied = snprintf(mCurBufferp, getBufferSize() - getCurrentSize(), "%d\n", value); /* Flawfinder: ignore */
}
else
{
numCopied = snprintf(DUMMY_BUFFER, sizeof(DUMMY_BUFFER), "%d\n", value); /* Flawfinder: ignore */
}
// snprintf returns number of bytes that would have been written
// had the output not being truncated. In that case, it will
// return either -1 or value >= passed in size value . So a check needs to be added
// to detect truncation, and if there is any, only account for the
// actual number of bytes written..and not what could have been
// written.
if(numCopied < 0 || numCopied > getBufferSize() - getCurrentSize())
{
numCopied = getBufferSize() - getCurrentSize();
LL_WARNS() << "LLDataPackerAsciiBuffer::packS16: val truncated: " << LL_ENDL;
}
mCurBufferp += numCopied;
return success;
}
BOOL LLDataPackerAsciiBuffer::unpackS16(S16 &value, const char *name)
{
BOOL success = TRUE;
char valuestr[DP_BUFSIZE]; /* Flawfinder: ignore */
if (!getValueStr(name, valuestr, DP_BUFSIZE))
{
return FALSE;
}
S32 in_val;
sscanf(valuestr, "%d", &in_val);
value = in_val;
return success;
}
BOOL LLDataPackerAsciiBuffer::packU32(const U32 value, const char *name)
{
@ -1642,6 +1776,36 @@ BOOL LLDataPackerAsciiFile::unpackU16(U16 &value, const char *name)
return success;
}
BOOL LLDataPackerAsciiFile::packS16(const S16 value, const char *name)
{
BOOL success = TRUE;
writeIndentedName(name);
if (mFP)
{
fprintf(mFP, "%d\n", value);
}
else if (mOutputStream)
{
*mOutputStream << "" << value << "\n";
}
return success;
}
BOOL LLDataPackerAsciiFile::unpackS16(S16 &value, const char *name)
{
BOOL success = TRUE;
char valuestr[DP_BUFSIZE]; /*Flawfinder: ignore */
if (!getValueStr(name, valuestr, DP_BUFSIZE))
{
return FALSE;
}
S32 in_val;
sscanf(valuestr, "%d", &in_val);
value = in_val;
return success;
}
BOOL LLDataPackerAsciiFile::packU32(const U32 value, const char *name)
{

View File

@ -62,6 +62,11 @@ public:
virtual BOOL packU16(const U16 value, const char *name) = 0;
virtual BOOL unpackU16(U16 &value, const char *name) = 0;
BOOL unpackU16s(U16 *value, S32 count, const char *name);
virtual BOOL packS16(const S16 value, const char *name) = 0;
virtual BOOL unpackS16(S16 &value, const char *name) = 0;
BOOL unpackS16s(S16 *value, S32 count, const char *name);
virtual BOOL packU32(const U32 value, const char *name) = 0;
virtual BOOL unpackU32(U32 &value, const char *name) = 0;
@ -71,6 +76,7 @@ public:
virtual BOOL packF32(const F32 value, const char *name) = 0;
virtual BOOL unpackF32(F32 &value, const char *name) = 0;
BOOL unpackF32s(F32 *values, S32 count, const char *name);
// Packs a float into an integer, using the given size
// and picks the right U* data type to pack into.
@ -84,6 +90,7 @@ public:
virtual BOOL packColor4U(const LLColor4U &value, const char *name) = 0;
virtual BOOL unpackColor4U(LLColor4U &value, const char *name) = 0;
BOOL unpackColor4Us(LLColor4U *values, S32 count, const char *name);
virtual BOOL packVector2(const LLVector2 &value, const char *name) = 0;
virtual BOOL unpackVector2(LLVector2 &value, const char *name) = 0;
@ -96,6 +103,7 @@ public:
virtual BOOL packUUID(const LLUUID &value, const char *name) = 0;
virtual BOOL unpackUUID(LLUUID &value, const char *name) = 0;
BOOL unpackUUIDs(LLUUID *values, S32 count, const char *name);
U32 getPassFlags() const { return mPassFlags; }
void setPassFlags(U32 flags) { mPassFlags = flags; }
protected:
@ -141,6 +149,9 @@ public:
/*virtual*/ BOOL packU16(const U16 value, const char *name);
/*virtual*/ BOOL unpackU16(U16 &value, const char *name);
/*virtual*/ BOOL packS16(const S16 value, const char *name);
/*virtual*/ BOOL unpackS16(S16 &value, const char *name);
/*virtual*/ BOOL packU32(const U32 value, const char *name);
/*virtual*/ BOOL unpackU32(U32 &value, const char *name);
@ -258,6 +269,9 @@ public:
/*virtual*/ BOOL packU16(const U16 value, const char *name);
/*virtual*/ BOOL unpackU16(U16 &value, const char *name);
/*virtual*/ BOOL packS16(const S16 value, const char *name);
/*virtual*/ BOOL unpackS16(S16 &value, const char *name);
/*virtual*/ BOOL packU32(const U32 value, const char *name);
/*virtual*/ BOOL unpackU32(U32 &value, const char *name);
@ -386,6 +400,9 @@ public:
/*virtual*/ BOOL packU16(const U16 value, const char *name);
/*virtual*/ BOOL unpackU16(U16 &value, const char *name);
/*virtual*/ BOOL packS16(const S16 value, const char *name);
/*virtual*/ BOOL unpackS16(S16 &value, const char *name);
/*virtual*/ BOOL packU32(const U32 value, const char *name);
/*virtual*/ BOOL unpackU32(U32 &value, const char *name);

View File

@ -46,6 +46,7 @@
#include "apr_poll.h"
// linden library headers
#include "llapp.h"
#include "indra_constants.h"
#include "lldir.h"
#include "llerror.h"

View File

@ -281,6 +281,13 @@ char const* const _PREHASH_PricePerMeter = LLMessageStringTable::getInstance()->
char const* const _PREHASH_RegionFlags = LLMessageStringTable::getInstance()->getString("RegionFlags");
char const* const _PREHASH_RegionFlagsExtended = LLMessageStringTable::getInstance()->getString("RegionFlagsExtended");
char const* const _PREHASH_RegionProtocols = LLMessageStringTable::getInstance()->getString("RegionProtocols");
char const* const _PREHASH_ChatWhisperRange = LLMessageStringTable::getInstance()->getString("ChatWhisperRange");
char const* const _PREHASH_ChatNormalRange = LLMessageStringTable::getInstance()->getString("ChatNormalRange");
char const* const _PREHASH_ChatShoutRange = LLMessageStringTable::getInstance()->getString("ChatShoutRange");
char const* const _PREHASH_ChatWhisperOffset = LLMessageStringTable::getInstance()->getString("ChatWhisperOffset");
char const* const _PREHASH_ChatNormalOffset = LLMessageStringTable::getInstance()->getString("ChatNormalOffset");
char const* const _PREHASH_ChatShoutOffset = LLMessageStringTable::getInstance()->getString("ChatShoutOffset");
char const* const _PREHASH_ChatFlags = LLMessageStringTable::getInstance()->getString("ChatFlags");
char const* const _PREHASH_VoteResult = LLMessageStringTable::getInstance()->getString("VoteResult");
char const* const _PREHASH_ParcelDirFeeEstimate = LLMessageStringTable::getInstance()->getString("ParcelDirFeeEstimate");
char const* const _PREHASH_ModifyBlock = LLMessageStringTable::getInstance()->getString("ModifyBlock");
@ -309,6 +316,7 @@ char const* const _PREHASH_DuplicateFlags = LLMessageStringTable::getInstance()-
char const* const _PREHASH_RegionInfo2 = LLMessageStringTable::getInstance()->getString("RegionInfo2");
char const* const _PREHASH_RegionInfo3 = LLMessageStringTable::getInstance()->getString("RegionInfo3");
char const* const _PREHASH_RegionInfo4 = LLMessageStringTable::getInstance()->getString("RegionInfo4");
char const* const _PREHASH_RegionInfo5 = LLMessageStringTable::getInstance()->getString("RegionInfo5");
char const* const _PREHASH_TextColor = LLMessageStringTable::getInstance()->getString("TextColor");
char const* const _PREHASH_SlaveID = LLMessageStringTable::getInstance()->getString("SlaveID");
char const* const _PREHASH_Charter = LLMessageStringTable::getInstance()->getString("Charter");

View File

@ -281,6 +281,13 @@ extern char const* const _PREHASH_PricePerMeter;
extern char const* const _PREHASH_RegionFlags;
extern char const* const _PREHASH_RegionFlagsExtended;
extern char const* const _PREHASH_RegionProtocols;
extern char const* const _PREHASH_ChatWhisperRange;
extern char const* const _PREHASH_ChatNormalRange;
extern char const* const _PREHASH_ChatShoutRange;
extern char const* const _PREHASH_ChatWhisperOffset;
extern char const* const _PREHASH_ChatNormalOffset;
extern char const* const _PREHASH_ChatShoutOffset;
extern char const* const _PREHASH_ChatFlags;
extern char const* const _PREHASH_VoteResult;
extern char const* const _PREHASH_ParcelDirFeeEstimate;
extern char const* const _PREHASH_ModifyBlock;
@ -309,6 +316,7 @@ extern char const* const _PREHASH_DuplicateFlags;
extern char const* const _PREHASH_RegionInfo2;
extern char const* const _PREHASH_RegionInfo3;
extern char const* const _PREHASH_RegionInfo4;
extern char const* const _PREHASH_RegionInfo5;
extern char const* const _PREHASH_TextColor;
extern char const* const _PREHASH_SlaveID;
extern char const* const _PREHASH_Charter;

View File

@ -285,11 +285,6 @@ const LLUUID SND_STONE_DIRT_04 ("c8091652-e04b-4a11-84ba-15dba06e7a1b");
const LLUUID SND_STONE_STONE_02 ("ba4ef5ac-7435-4240-b826-c24ba8fa5a78");
const LLUUID SND_STONE_STONE_04 ("ea296329-0f09-4993-af1b-e6784bab1dc9");
// NaCl - Antispam Registry. The following sounds will be ignored for purposes of spam protection. They have been gathered from wiki documentation of frequent official sounds.
const std::string COLLISION_SOUNDS[] ={"dce5fdd4-afe4-4ea1-822f-dd52cac46b08","51011582-fbca-4580-ae9e-1a5593f094ec","68d62208-e257-4d0c-bbe2-20c9ea9760bb","75872e8c-bc39-451b-9b0b-042d7ba36cba","6a45ba0b-5775-4ea8-8513-26008a17f873","992a6d1b-8c77-40e0-9495-4098ce539694","2de4da5a-faf8-46be-bac6-c4d74f1e5767","6e3fb0f7-6d9c-42ca-b86b-1122ff562d7d","14209133-4961-4acc-9649-53fc38ee1667","bc4a4348-cfcc-4e5e-908e-8a52a8915fe6","9e5c1297-6eed-40c0-825a-d9bcd86e3193","e534761c-1894-4b61-b20c-658a6fb68157","8761f73f-6cf9-4186-8aaa-0948ed002db1","874a26fd-142f-4173-8c5b-890cd846c74d","0e24a717-b97e-4b77-9c94-b59a5a88b2da","75cf3ade-9a5b-4c4d-bb35-f9799bda7fb2","153c8bf7-fb89-4d89-b263-47e58b1b4774","55c3e0ce-275a-46fa-82ff-e0465f5e8703","24babf58-7156-4841-9a3f-761bdbb8e237","aca261d8-e145-4610-9e20-9eff990f2c12","0642fba6-5dcf-4d62-8e7b-94dbb529d117","25a863e8-dc42-4e8a-a357-e76422ace9b5","9538f37c-456e-4047-81be-6435045608d4","8c0f84c3-9afd-4396-b5f5-9bca2c911c20","be582e5d-b123-41a2-a150-454c39e961c8","c70141d4-ba06-41ea-bcbc-35ea81cb8335","7d1826f4-24c4-4aac-8c2e-eff45df37783","063c97d3-033a-4e9b-98d8-05c8074922cb","00000000-0000-0000-0000-000000000120"};
const int COLLISION_SOUNDS_SIZE=29;
// NaCl End
// extra guids

View File

@ -286,9 +286,4 @@ extern const LLUUID SND_STONE_DIRT_04;
extern const LLUUID SND_STONE_STONE_02;
extern const LLUUID SND_STONE_STONE_04;
// NaCl - Antispam Registry
extern const std::string COLLISION_SOUNDS[];
extern const int COLLISION_SOUNDS_SIZE;
// NaCl End
#endif

View File

@ -696,6 +696,66 @@ bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers, LLSD
return true;
}
// This function injects a previously stored OpenID cookie into
// each new media instance - see SL-15867 for details. It appears
// that the way we use the cache, shared between multiple CEF
// instances means that sometimes the OpenID cookie cannot be read
// even though it appears to be there. The long term solution to
// this is to create a separate cache directory for each instance
// but that has its own set of problems. This short term approach
// "forces" each new media instance to have a copy of the cookie
// so that a page that needs it - e.g. Profiles - finds it and
// can log in successfully.
void LLPluginClassMedia::injectOpenIDCookie()
{
// can be called before we know who the user is at login
// and there is no OpenID cookie at that point so no
// need to try to set it (these values will all be empty)
if (sOIDcookieName.length() && sOIDcookieValue.length())
{
setCookie(sOIDcookieUrl, sOIDcookieName,
sOIDcookieValue, sOIDcookieHost, sOIDcookiePath, sOIDcookieHttpOnly, sOIDcookieSecure);
}
}
// We store each component of the OpenI cookie individuality here
// because previously, there was some significant parsing to
// break up the raw string into these components and we do not
// want to have to do that again here. Stored as statics because
// we want to share their value between all instances of this
// class - the ones that receive it at login and any others
// that open afterwards (e.g. the Profiles floater)
std::string LLPluginClassMedia::sOIDcookieUrl = std::string();
std::string LLPluginClassMedia::sOIDcookieName = std::string();
std::string LLPluginClassMedia::sOIDcookieValue = std::string();
std::string LLPluginClassMedia::sOIDcookieHost = std::string();
std::string LLPluginClassMedia::sOIDcookiePath = std::string();
bool LLPluginClassMedia::sOIDcookieHttpOnly = false;
bool LLPluginClassMedia::sOIDcookieSecure = false;
// Once we receive the OpenID cookie, it is parsed/processed
// in llViewerMedia::parseRawCookie() and then the component
// values are stored here so that next time a new media
// instance is created, we can use injectOpenIDCookie()
// to "insist" that the cookie store remember its value.
// One might ask why we need to go via LLViewerMedia (which
// makes this call) - this is because the raw cookie arrives
// here in this file but undergoes non-trivial processing
// in LLViewerMedia.
void LLPluginClassMedia::storeOpenIDCookie(const std::string url,
const std::string name, const std::string value,
const std::string host, const std::string path,
bool httponly, bool secure)
{
sOIDcookieUrl = url;
sOIDcookieName = name;
sOIDcookieValue = value;
sOIDcookieHost = host;
sOIDcookiePath = path;
sOIDcookieHttpOnly = httponly;
sOIDcookieSecure = secure;
}
void LLPluginClassMedia::setCookie(std::string uri, std::string name, std::string value, std::string domain, std::string path, bool httponly, bool secure)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_cookie");
@ -720,6 +780,15 @@ void LLPluginClassMedia::loadURI(const std::string &uri)
sendMessage(message);
}
void LLPluginClassMedia::executeJavaScript(const std::string &code)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "execute_javascript");
message.setValue("code", code);
sendMessage(message);
}
const char* LLPluginClassMedia::priorityToString(EPriority priority)
{
const char* result = "UNKNOWN";
@ -897,6 +966,19 @@ void LLPluginClassMedia::setJavascriptEnabled(const bool enabled)
sendMessage(message);
}
void LLPluginClassMedia::setWebSecurityDisabled(const bool disabled)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "web_security_disabled");
message.setValueBoolean("disabled", disabled);
sendMessage(message);
}
void LLPluginClassMedia::setFileAccessFromFileUrlsEnabled(const bool enabled)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "file_access_from_file_urls");
message.setValueBoolean("enabled", enabled);
sendMessage(message);
}
void LLPluginClassMedia::enableMediaPluginDebugging( bool enable )
{

View File

@ -135,10 +135,26 @@ public:
// Text may be unicode (utf8 encoded)
bool textInput(const std::string &text, MASK modifiers, LLSD native_key_data);
static std::string sOIDcookieUrl;
static std::string sOIDcookieName;
static std::string sOIDcookieValue;
static std::string sOIDcookieHost;
static std::string sOIDcookiePath;
static bool sOIDcookieHttpOnly;
static bool sOIDcookieSecure;
void storeOpenIDCookie(const std::string url,
const std::string name, const std::string value,
const std::string host, const std::string path,
bool httponly, bool secure);
void injectOpenIDCookie();
void setCookie(std::string uri, std::string name, std::string value, std::string domain, std::string path, bool httponly, bool secure);
void loadURI(const std::string &uri);
void executeJavaScript(const std::string &code);
// "Loading" means uninitialized or any state prior to fully running (processing commands)
bool isPluginLoading(void) { return mPlugin?mPlugin->isLoading():false; };
@ -199,6 +215,8 @@ public:
void setLanguageCode(const std::string &language_code);
void setPluginsEnabled(const bool enabled);
void setJavascriptEnabled(const bool enabled);
void setWebSecurityDisabled(const bool disabled);
void setFileAccessFromFileUrlsEnabled(const bool enabled);
void setTarget(const std::string &target);
///////////////////////////////////

View File

@ -28,6 +28,7 @@
#include "linden_common.h"
#include "llapp.h"
#include "llpluginprocessparent.h"
#include "llpluginmessagepipe.h"
#include "llpluginmessageclasses.h"

View File

@ -559,6 +559,23 @@ LLUUID LLMaterialTable::getCollisionSoundUUID(U8 mcode, U8 mcode2)
}
}
bool LLMaterialTable::isCollisionSound(const LLUUID &uuid)
{
for (U8 i = 0; i < LL_MCODE_END; i++)
{
for (U8 j = 0; j < LL_MCODE_END; j++)
{
i &= LL_MCODE_MASK;
j &= LL_MCODE_MASK;
if (mCollisionSoundMatrix[i * LL_MCODE_END + j] == uuid)
{
return true;
}
}
}
return false;
}
LLUUID LLMaterialTable::getSlidingSoundUUID(U8 mcode, U8 mcode2)
{
mcode &= LL_MCODE_MASK;

View File

@ -128,6 +128,8 @@ public:
F32 getDamageMod(U8 mcode);
F32 getEPMod(U8 mcode);
bool isCollisionSound(const LLUUID &uuid);
LLUUID getCollisionSoundUUID(U8 mcode, U8 mcode2);
LLUUID getSlidingSoundUUID(U8 mcode, U8 mcode2);
LLUUID getRollingSoundUUID(U8 mcode, U8 mcode2);

View File

@ -27,8 +27,7 @@
#include "linden_common.h"
#include "llmediaentry.h"
#include "lllslconstants.h"
#include <boost/regex.hpp>
#include "llregex.h"
// LLSD key defines
// DO NOT REORDER OR REMOVE THESE!
@ -456,7 +455,7 @@ static bool pattern_match(const std::string &candidate_str, const std::string &p
// case-insensitive matching:
boost::regex regexp(expression, boost::regex::perl|boost::regex::icase);
return boost::regex_match(candidate_str, regexp);
return ll_regex_match(candidate_str, regexp);
}
bool LLMediaEntry::checkCandidateUrl(const std::string& url) const

View File

@ -122,6 +122,35 @@ const char *SCULPT_DEFAULT_TEXTURE = "be293869-d0d9-0a69-5989-ad27f1946fd4"; //
// can't be divided by 2. See DEV-19108
const F32 TEXTURE_ROTATION_PACK_FACTOR = ((F32) 0x08000);
struct material_id_type // originally from llrendermaterialtable
{
material_id_type()
{
memset((void*)m_value, 0, sizeof(m_value));
}
bool operator==(const material_id_type& other) const
{
return (memcmp(m_value, other.m_value, sizeof(m_value)) == 0);
}
bool operator!=(const material_id_type& other) const
{
return !operator==(other);
}
bool isNull() const
{
return (memcmp(m_value, s_null_id, sizeof(m_value)) == 0);
}
U8 m_value[MATERIAL_ID_SIZE]; // server side this is MD5RAW_BYTES
static const U8 s_null_id[MATERIAL_ID_SIZE];
};
const U8 material_id_type::s_null_id[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
//static
// LEGACY: by default we use the LLVolumeMgr::gVolumeMgr global
// TODO -- eliminate this global from the codebase!
@ -1092,50 +1121,85 @@ S32 LLPrimitive::packTEField(U8 *cur_ptr, U8 *data_ptr, U8 data_size, U8 last_fa
return (S32)(cur_ptr - start_loc);
}
S32 LLPrimitive::unpackTEField(U8 *cur_ptr, U8 *buffer_end, U8 *data_ptr, U8 data_size, U8 face_count, EMsgVariableType type)
namespace
{
U8 *start_loc = cur_ptr;
U64 i;
htolememcpy(data_ptr,cur_ptr, type,data_size);
cur_ptr += data_size;
template< typename T >
bool unpack_TEField(T dest[], U8 dest_count, U8 * &source, U8 *source_end, EMsgVariableType type)
{
const size_t size(sizeof(T));
for (i = 1; i < face_count; i++)
{
// Already unswizzled, don't need to unswizzle it again!
memcpy(data_ptr+(i*data_size),data_ptr,data_size); /* Flawfinder: ignore */
}
while ((cur_ptr < buffer_end) && (*cur_ptr != 0))
{
LL_DEBUGS("TEFieldDecode") << "TE exception" << LL_ENDL;
i = 0;
while (*cur_ptr & 0x80)
{
i |= ((*cur_ptr++) & 0x7F);
i = i << 7;
}
LL_DEBUGS("TEXTUREENTRY") << "Request to read items of size " << size << " with swizzle " << type << " froum buffer sized " << (source_end - source) << LL_ENDL;
i |= *cur_ptr++;
if ((source + size + 1) > source_end)
{
// we add 1 above to take into account the byte that we know must follow the value.
LL_WARNS("TEXTUREENTRY") << "Buffer exhausted! Requires " << size << " + 1 bytes for default, " << (source_end - source) << " bytes remaning." << LL_ENDL;
source = source_end;
return false;
}
for (S32 j = 0; j < face_count; j++)
{
if (i & 0x01)
{
htolememcpy(data_ptr+(j*data_size),cur_ptr,type,data_size);
LL_DEBUGS("TEFieldDecode") << "Assigning " ;
char foo[64];
sprintf(foo,"%x %x",*(data_ptr+(j*data_size)), *(data_ptr+(j*data_size)+1));
LL_CONT << foo << " to face " << j << LL_ENDL;
}
i = i >> 1;
}
cur_ptr += data_size;
}
llassert(cur_ptr <= buffer_end); // buffer underrun
return (S32)(cur_ptr - start_loc);
// Extract the default value and fill the array.
htolememcpy(dest, source, type, size);
source += size;
for (S32 idx = 1; idx < dest_count; ++idx)
{
dest[idx] = dest[0];
}
while (source < source_end)
{
U64 index_flags(0);
U8 sbit(0);
// Unpack the variable length bitfield. Each bit represents whether the following
// value will be placed at the corresponding array index.
do
{
if (source >= source_end)
{
LL_WARNS("TEXTUREENTRY") << "Buffer exhausted! Reading index flags." << LL_ENDL;
source = source_end;
return false;
}
sbit = *source++;
index_flags <<= 7; // original code had this after?
index_flags |= (sbit & 0x7F);
} while (sbit & 0x80);
if (!index_flags)
{ // We've hit the terminating 0 byte.
break;
}
if ((source + size + 1) > source_end)
{
// we add 1 above to take into account the byte that we know must follow the value.
LL_WARNS("TEXTUREENTRY") << "Buffer exhausted! Requires " << size << " + 1 bytes for default, " << (source_end - source) << " bytes remaning." << LL_ENDL;
source = source_end;
return false;
}
// get the value for the indexs.
T value;
htolememcpy(&value, source, type, size);
source += size;
for (S32 idx = 0; idx < dest_count; idx++)
{
if (index_flags & 1ULL << idx)
{
dest[idx] = value;
}
}
}
return true;
}
}
// Pack information about all texture entries into container:
// { TextureEntry Variable 2 }
// Includes information about image ID, color, scale S,T, offset S,T and rotation
@ -1312,9 +1376,9 @@ BOOL LLPrimitive::packTEMessage(LLDataPacker &dp) const
S32 LLPrimitive::parseTEMessage(LLMessageSystem* mesgsys, char const* block_name, const S32 block_num, LLTEContents& tec)
{
S32 retval = 0;
// temp buffer for material ID processing
// data will end up in tec.material_id[]
U8 material_data[LLTEContents::MAX_TES*16];
// temp buffer for material ID processing
// data will end up in tec.material_id[]
material_id_type material_data[LLTEContents::MAX_TES];
if (block_num < 0)
{
@ -1330,54 +1394,49 @@ S32 LLPrimitive::parseTEMessage(LLMessageSystem* mesgsys, char const* block_name
tec.face_count = 0;
return retval;
}
else if (tec.size >= LLTEContents::MAX_TE_BUFFER)
{
LL_WARNS("TEXTUREENTRY") << "Excessive buffer size detected in Texture Entry! Truncating." << LL_ENDL;
tec.size = LLTEContents::MAX_TE_BUFFER - 1;
}
if (block_num < 0)
{
mesgsys->getBinaryDataFast(block_name, _PREHASH_TextureEntry, tec.packed_buffer, 0, 0, LLTEContents::MAX_TE_BUFFER);
}
else
{
mesgsys->getBinaryDataFast(block_name, _PREHASH_TextureEntry, tec.packed_buffer, 0, block_num, LLTEContents::MAX_TE_BUFFER);
}
// if block_num < 0 ask for block 0
mesgsys->getBinaryDataFast(block_name, _PREHASH_TextureEntry, tec.packed_buffer, 0, std::max(block_num, 0), LLTEContents::MAX_TE_BUFFER - 1);
// The last field is not zero terminated.
// Rather than special case the upack functions. Just make it 0x00 terminated.
tec.packed_buffer[tec.size] = 0x00;
++tec.size;
tec.face_count = llmin((U32)getNumTEs(),(U32)LLTEContents::MAX_TES);
U8 *cur_ptr = tec.packed_buffer;
cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.image_data, 16, tec.face_count, MVT_LLUUID);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.colors, 4, tec.face_count, MVT_U8);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.scale_s, 4, tec.face_count, MVT_F32);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.scale_t, 4, tec.face_count, MVT_F32);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.offset_s, 2, tec.face_count, MVT_S16Array);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.offset_t, 2, tec.face_count, MVT_S16Array);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.image_rot, 2, tec.face_count, MVT_S16Array);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.bump, 1, tec.face_count, MVT_U8);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.media_flags, 1, tec.face_count, MVT_U8);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.glow, 1, tec.face_count, MVT_U8);
LL_DEBUGS("TEXTUREENTRY") << "Texture Entry with buffere sized: " << tec.size << LL_ENDL;
U8 *buffer_end = tec.packed_buffer + tec.size;
if (cur_ptr < tec.packed_buffer + tec.size)
if (!( unpack_TEField<LLUUID>(tec.image_data, tec.face_count, cur_ptr, buffer_end, MVT_LLUUID) &&
unpack_TEField<LLColor4U>(tec.colors, tec.face_count, cur_ptr, buffer_end, MVT_U8) &&
unpack_TEField<F32>(tec.scale_s, tec.face_count, cur_ptr, buffer_end, MVT_F32) &&
unpack_TEField<F32>(tec.scale_t, tec.face_count, cur_ptr, buffer_end, MVT_F32) &&
unpack_TEField<S16>(tec.offset_s, tec.face_count, cur_ptr, buffer_end, MVT_S16) &&
unpack_TEField<S16>(tec.offset_t, tec.face_count, cur_ptr, buffer_end, MVT_S16) &&
unpack_TEField<S16>(tec.image_rot, tec.face_count, cur_ptr, buffer_end, MVT_S16) &&
unpack_TEField<U8>(tec.bump, tec.face_count, cur_ptr, buffer_end, MVT_U8) &&
unpack_TEField<U8>(tec.media_flags, tec.face_count, cur_ptr, buffer_end, MVT_U8) &&
unpack_TEField<U8>(tec.glow, tec.face_count, cur_ptr, buffer_end, MVT_U8)))
{
LL_WARNS("TEXTUREENTRY") << "Failure parsing Texture Entry Message due to malformed TE Field! Dropping changes on the floor. " << LL_ENDL;
return 0;
}
if (cur_ptr >= buffer_end || !unpack_TEField<material_id_type>(material_data, tec.face_count, cur_ptr, buffer_end, MVT_LLUUID))
{
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)material_data, 16, tec.face_count, MVT_LLUUID);
}
else
{
memset(material_data, 0, sizeof(material_data));
memset((void*)material_data, 0, sizeof(material_data));
}
for (U32 i = 0; i < tec.face_count; i++)
{
tec.material_ids[i].set(&material_data[i * 16]);
tec.material_ids[i].set(&(material_data[i]));
}
retval = 1;
@ -1389,7 +1448,6 @@ S32 LLPrimitive::applyParsedTEMessage(LLTEContents& tec)
S32 retval = 0;
LLColor4 color;
LLColor4U coloru;
for (U32 i = 0; i < tec.face_count; i++)
{
LLUUID& req_id = ((LLUUID*)tec.image_data)[i];
@ -1402,20 +1460,15 @@ S32 LLPrimitive::applyParsedTEMessage(LLTEContents& tec)
retval |= setTEGlow(i, (F32)tec.glow[i] / (F32)0xFF);
retval |= setTEMaterialID(i, tec.material_ids[i]);
coloru = LLColor4U(tec.colors + 4*i);
// Note: This is an optimization to send common colors (1.f, 1.f, 1.f, 1.f)
// as all zeros. However, the subtraction and addition must be done in unsigned
// byte space, not in float space, otherwise off-by-one errors occur. JC
color.mV[VRED] = F32(255 - coloru.mV[VRED]) / 255.f;
color.mV[VGREEN] = F32(255 - coloru.mV[VGREEN]) / 255.f;
color.mV[VBLUE] = F32(255 - coloru.mV[VBLUE]) / 255.f;
color.mV[VALPHA] = F32(255 - coloru.mV[VALPHA]) / 255.f;
color.mV[VRED] = F32(255 - tec.colors[i].mV[VRED]) / 255.f;
color.mV[VGREEN] = F32(255 - tec.colors[i].mV[VGREEN]) / 255.f;
color.mV[VBLUE] = F32(255 - tec.colors[i].mV[VBLUE]) / 255.f;
color.mV[VALPHA] = F32(255 - tec.colors[i].mV[VALPHA]) / 255.f;
retval |= setTEColor(i, color);
}
return retval;
@ -1437,24 +1490,32 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp)
const U32 MAX_TES = 45;
// Avoid construction of 32 UUIDs per call
static LLUUID image_ids[MAX_TES];
static LLMaterialID material_ids[MAX_TES];
U8 image_data[MAX_TES*16];
U8 colors[MAX_TES*4];
F32 scale_s[MAX_TES];
F32 scale_t[MAX_TES];
S16 offset_s[MAX_TES];
S16 offset_t[MAX_TES];
S16 image_rot[MAX_TES];
U8 bump[MAX_TES];
U8 media_flags[MAX_TES];
U8 glow[MAX_TES];
U8 material_data[MAX_TES*16];
const U32 MAX_TE_BUFFER = 4096;
U8 packed_buffer[MAX_TE_BUFFER];
memset((void*)packed_buffer, 0, MAX_TE_BUFFER);
const U32 MAX_TE_BUFFER = 4096;
U8 packed_buffer[MAX_TE_BUFFER];
U8 *cur_ptr = packed_buffer;
LLUUID image_data[MAX_TES];
LLColor4U colors[MAX_TES];
F32 scale_s[MAX_TES];
F32 scale_t[MAX_TES];
S16 offset_s[MAX_TES];
S16 offset_t[MAX_TES];
S16 image_rot[MAX_TES];
U8 bump[MAX_TES];
U8 media_flags[MAX_TES];
U8 glow[MAX_TES];
material_id_type material_data[MAX_TES];
memset((void*)scale_s, 0, sizeof(scale_s));
memset((void*)scale_t, 0, sizeof(scale_t));
memset((void*)offset_s, 0, sizeof(offset_s));
memset((void*)offset_t, 0, sizeof(offset_t));
memset((void*)image_rot, 0, sizeof(image_rot));
memset((void*)bump, 0, sizeof(bump));
memset((void*)media_flags, 0, sizeof(media_flags));
memset((void*)glow, 0, sizeof(glow));
S32 size;
U32 face_count = 0;
@ -1470,50 +1531,52 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp)
{
return retval;
}
else if (size >= MAX_TE_BUFFER)
{
LL_WARNS("TEXTUREENTRY") << "Excessive buffer size detected in Texture Entry! Truncating." << LL_ENDL;
size = MAX_TE_BUFFER - 1;
}
// The last field is not zero terminated.
// Rather than special case the upack functions. Just make it 0x00 terminated.
packed_buffer[size] = 0x00;
++size;
face_count = llmin((U32) getNumTEs(), MAX_TES);
U32 i;
cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)image_data, 16, face_count, MVT_LLUUID);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)colors, 4, face_count, MVT_U8);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)scale_s, 4, face_count, MVT_F32);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)scale_t, 4, face_count, MVT_F32);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)offset_s, 2, face_count, MVT_S16Array);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)offset_t, 2, face_count, MVT_S16Array);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)image_rot, 2, face_count, MVT_S16Array);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)bump, 1, face_count, MVT_U8);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)media_flags, 1, face_count, MVT_U8);
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)glow, 1, face_count, MVT_U8);
if (cur_ptr < packed_buffer + size)
U8 *cur_ptr = packed_buffer;
LL_DEBUGS("TEXTUREENTRY") << "Texture Entry with buffer sized: " << size << LL_ENDL;
U8 *buffer_end = packed_buffer + size;
if (!( unpack_TEField<LLUUID>(image_data, face_count, cur_ptr, buffer_end, MVT_LLUUID) &&
unpack_TEField<LLColor4U>(colors, face_count, cur_ptr, buffer_end, MVT_U8) &&
unpack_TEField<F32>(scale_s, face_count, cur_ptr, buffer_end, MVT_F32) &&
unpack_TEField<F32>(scale_t, face_count, cur_ptr, buffer_end, MVT_F32) &&
unpack_TEField<S16>(offset_s, face_count, cur_ptr, buffer_end, MVT_S16) &&
unpack_TEField<S16>(offset_t, face_count, cur_ptr, buffer_end, MVT_S16) &&
unpack_TEField<S16>(image_rot, face_count, cur_ptr, buffer_end, MVT_S16) &&
unpack_TEField<U8>(bump, face_count, cur_ptr, buffer_end, MVT_U8) &&
unpack_TEField<U8>(media_flags, face_count, cur_ptr, buffer_end, MVT_U8) &&
unpack_TEField<U8>(glow, face_count, cur_ptr, buffer_end, MVT_U8)))
{
LL_WARNS("TEXTUREENTRY") << "Failure parsing Texture Entry Message due to malformed TE Field! Dropping changes on the floor. " << LL_ENDL;
return 0;
}
if (cur_ptr >= buffer_end || !unpack_TEField<material_id_type>(material_data, face_count, cur_ptr, buffer_end, MVT_LLUUID))
{
cur_ptr++;
cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)material_data, 16, face_count, MVT_LLUUID);
}
else
{
memset(material_data, 0, sizeof(material_data));
memset((void*)material_data, 0, sizeof(material_data));
}
for (i = 0; i < face_count; i++)
{
memcpy( image_ids[ i ].mData, &image_data[ i*UUID_BYTES ], UUID_BYTES ); /* Flawfinder: ignore */
material_ids[ i ].set( &material_data[ i * UUID_BYTES ] );
material_ids[i].set(&(material_data[i]));
}
LLColor4 color;
LLColor4U coloru;
for (i = 0; i < face_count; i++)
{
retval |= setTETexture(i, image_ids[i]);
retval |= setTETexture(i, ((LLUUID*)image_data)[i]);
retval |= setTEScale(i, scale_s[i], scale_t[i]);
retval |= setTEOffset(i, (F32)offset_s[i] / (F32)0x7FFF, (F32) offset_t[i] / (F32) 0x7FFF);
retval |= setTERotation(i, ((F32)image_rot[i] / TEXTURE_ROTATION_PACK_FACTOR) * F_TWO_PI);
@ -1521,15 +1584,14 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp)
retval |= setTEMediaTexGen(i, media_flags[i]);
retval |= setTEGlow(i, (F32)glow[i] / (F32)0xFF);
retval |= setTEMaterialID(i, material_ids[i]);
coloru = LLColor4U(colors + 4*i);
// Note: This is an optimization to send common colors (1.f, 1.f, 1.f, 1.f)
// as all zeros. However, the subtraction and addition must be done in unsigned
// byte space, not in float space, otherwise off-by-one errors occur. JC
color.mV[VRED] = F32(255 - coloru.mV[VRED]) / 255.f;
color.mV[VGREEN] = F32(255 - coloru.mV[VGREEN]) / 255.f;
color.mV[VBLUE] = F32(255 - coloru.mV[VBLUE]) / 255.f;
color.mV[VALPHA] = F32(255 - coloru.mV[VALPHA]) / 255.f;
color.mV[VRED] = F32(255 - colors[i].mV[VRED]) / 255.f;
color.mV[VGREEN] = F32(255 - colors[i].mV[VGREEN]) / 255.f;
color.mV[VBLUE] = F32(255 - colors[i].mV[VBLUE]) / 255.f;
color.mV[VALPHA] = F32(255 - colors[i].mV[VALPHA]) / 255.f;
retval |= setTEColor(i, color);
}

View File

@ -338,8 +338,8 @@ struct LLTEContents
{
static const U32 MAX_TES = 45;
U8 image_data[MAX_TES*16];
U8 colors[MAX_TES*4];
LLUUID image_data[MAX_TES];
LLColor4U colors[MAX_TES];
F32 scale_s[MAX_TES];
F32 scale_t[MAX_TES];
S16 offset_s[MAX_TES];
@ -432,7 +432,6 @@ public:
void copyTEs(const LLPrimitive *primitive);
S32 packTEField(U8 *cur_ptr, U8 *data_ptr, U8 data_size, U8 last_face_index, EMsgVariableType type) const;
S32 unpackTEField(U8 *cur_ptr, U8 *buffer_end, U8 *data_ptr, U8 data_size, U8 face_count, EMsgVariableType type);
BOOL packTEMessage(LLMessageSystem *mesgsys) const;
BOOL packTEMessage(LLDataPacker &dp) const;
S32 unpackTEMessage(LLMessageSystem* mesgsys, char const* block_name, const S32 block_num); // Variable num of blocks

View File

@ -1065,6 +1065,43 @@ void LLComboBox::prearrangeList(std::string filter)
}
}
//============================================================================
// ll::ui::SearchableControl functions
//virtual
std::string LLComboBox::_getSearchText() const
{
std::string res;
if (mList)
{
// getAllData returns a full copy of content, might be a
// better option to implement an mList->getSearchText(column)
std::vector<LLScrollListItem*> data = mList->getAllData();
std::vector<LLScrollListItem*>::iterator iter = data.begin();
while (iter != data.end())
{
LLScrollListCell* cell = (*iter)->getColumn(0);
if (cell)
{
std::string whitelist_url = cell->getValue().asString();
res += cell->getValue().asString();
}
iter++;
}
}
return res + getToolTip();
}
//virtual
void LLComboBox::onSetHighlight() const
{
if (mButton)
{
mButton->ll::ui::SearchableControl::setHighlighted(ll::ui::SearchableControl::getHighlighted());
}
}
//============================================================================
// LLCtrlListInterface functions

View File

@ -44,7 +44,9 @@ class LLFontGL;
class LLViewBorder;
class LLComboBox
: public LLUICtrl, public LLCtrlListInterface
: public LLUICtrl
, public LLCtrlListInterface
, public ll::ui::SearchableControl
{
public:
typedef enum e_preferred_position
@ -101,6 +103,9 @@ protected:
void initFromParams(const Params&);
void prearrangeList(std::string filter = "");
virtual std::string _getSearchText() const;
virtual void onSetHighlight() const;
public:
// LLView interface
virtual void onFocusLost();

View File

@ -290,7 +290,8 @@ LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p)
mDefaultRelativeX(p.rel_x),
mDefaultRelativeY(p.rel_y),
mMinimizeSignal(NULL),
mHostedFloaterShowtitlebar(p.hosted_floater_show_titlebar) // <FS:Ansariel> MultiFloater without titlebar for hosted floater
mHostedFloaterShowtitlebar(p.hosted_floater_show_titlebar), // <FS:Ansariel> MultiFloater without titlebar for hosted floater
mShiftPressed(false) // <FS:Ansariel> FIRE-24125: Add option to close all floaters of a group
// mNotificationContext(NULL)
{
mPosition.setFloater(*this);
@ -1717,6 +1718,30 @@ BOOL LLFloater::handleDoubleClick(S32 x, S32 y, MASK mask)
return was_minimized || LLPanel::handleDoubleClick(x, y, mask);
}
// <FS:Ansariel> FIRE-24125: Add option to close all floaters of a group
//virtual
BOOL LLFloater::handleKeyHere(KEY key, MASK mask)
{
if (mask == MASK_SHIFT)
{
mShiftPressed = true;
}
return LLPanel::handleKeyHere(key, mask);
}
//virtual
BOOL LLFloater::handleKeyUpHere(KEY key, MASK mask)
{
if (mask == MASK_SHIFT)
{
mShiftPressed = false;
}
return LLPanel::handleKeyUpHere(key, mask);
}
// </FS:Ansariel>
void LLFloater::bringToFront( S32 x, S32 y )
{
if (getVisible() && pointInView(x, y))
@ -1965,6 +1990,20 @@ void LLFloater::onClickClose( LLFloater* self )
void LLFloater::onClickCloseBtn(bool app_quitting)
{
// <FS:Ansariel> FIRE-24125: Add option to close all floaters of a group
if (mShiftPressed)
{
auto floaterlist = LLFloaterReg::getAllFloatersInGroup(this);
for (auto floater : floaterlist)
{
if (floater != this)
{
floater->closeFloater();
}
}
}
// </FS:Ansariel>
closeFloater(false);
}

View File

@ -310,7 +310,12 @@ public:
virtual BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask);
virtual BOOL handleScrollWheel(S32 x, S32 y, S32 mask);
// <FS:Ansariel> FIRE-24125: Add option to close all floaters of a group
virtual BOOL handleKeyHere(KEY key, MASK mask);
virtual BOOL handleKeyUpHere(KEY key, MASK mask);
// </FS:Ansariel>
virtual void draw();
virtual void drawShadow(LLPanel* panel);
@ -555,6 +560,9 @@ private:
// <FS:Ansariel> MultiFloater without titlebar for hosted floater
bool mHostedFloaterShowtitlebar;
// <FS:Ansariel> FIRE-24125: Add option to close all floaters of a group
bool mShiftPressed;
};

View File

@ -103,6 +103,37 @@ LLFloater* LLFloaterReg::getLastFloaterInGroup(const std::string& name)
return NULL;
}
// <FS:Ansariel> FIRE-24125: Add option to close all floaters of a group
//static
LLFloaterReg::instance_list_t LLFloaterReg::getAllFloatersInGroup(LLFloater* floater)
{
if (floater)
{
for (const auto& group : sGroupMap)
{
const std::string& group_name = group.second;
if (group_name.empty())
{
continue;
}
instance_list_t& instances = sInstanceMap[group_name];
for (auto instance : instances)
{
if (instance == floater)
{
return sInstanceMap[group_name];
}
}
}
}
return {};
}
// </FS:Ansariel>
LLFloater* LLFloaterReg::getLastFloaterCascading()
{
LLRect candidate_rect;

View File

@ -114,6 +114,7 @@ public:
// Helpers
static LLFloater* getLastFloaterInGroup(const std::string& name);
static LLFloater* getLastFloaterCascading();
static instance_list_t getAllFloatersInGroup(LLFloater* floater); // <FS:Ansariel> FIRE-24125: Add option to close all floaters of a group
// Find / get (create) / remove / destroy
static LLFloater* findInstance(const std::string& name, const LLSD& key = LLSD());

View File

@ -84,7 +84,6 @@
#include <sstream>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/type_traits.hpp>
#include <boost/signals2.hpp>
#include <boost/range.hpp>
@ -132,7 +131,7 @@ public:
typedef boost::function<void (const LLSD&, const LLSD&)> LLNotificationResponder;
typedef boost::shared_ptr<LLNotificationResponderInterface> LLNotificationResponderPtr;
typedef std::shared_ptr<LLNotificationResponderInterface> LLNotificationResponderPtr;
typedef LLFunctorRegistry<LLNotificationResponder> LLNotificationFunctorRegistry;
typedef LLFunctorRegistration<LLNotificationResponder> LLNotificationFunctorRegistration;
@ -278,19 +277,19 @@ private:
bool mInvertSetting;
};
typedef boost::shared_ptr<LLNotificationForm> LLNotificationFormPtr;
typedef std::shared_ptr<LLNotificationForm> LLNotificationFormPtr;
struct LLNotificationTemplate;
// we want to keep a map of these by name, and it's best to manage them
// with smart pointers
typedef boost::shared_ptr<LLNotificationTemplate> LLNotificationTemplatePtr;
typedef std::shared_ptr<LLNotificationTemplate> LLNotificationTemplatePtr;
struct LLNotificationVisibilityRule;
typedef boost::shared_ptr<LLNotificationVisibilityRule> LLNotificationVisibilityRulePtr;
typedef std::shared_ptr<LLNotificationVisibilityRule> LLNotificationVisibilityRulePtr;
/**
* @class LLNotification
@ -764,6 +763,10 @@ public:
{}
virtual ~LLNotificationChannelBase()
{
// explicit cleanup for easier issue detection
mChanged.disconnect_all_slots();
mPassedFilter.disconnect_all_slots();
mFailedFilter.disconnect_all_slots();
mItems.clear();
}
// you can also connect to a Channel, so you can be notified of

View File

@ -31,7 +31,6 @@
#include "lleventapi.h"
#include "llnotificationptr.h"
#include <boost/shared_ptr.hpp>
#include <map>
#include <string>
@ -61,7 +60,7 @@ private:
static LLSD asLLSD(LLNotificationPtr);
class Forwarder;
typedef std::map<std::string, boost::shared_ptr<Forwarder> > ForwarderMap;
typedef std::map<std::string, std::shared_ptr<Forwarder> > ForwarderMap;
ForwarderMap mForwarders;
LLNotifications & mNotifications;
};

View File

@ -31,7 +31,7 @@
#include "llinitparam.h"
#include "llnotifications.h"
typedef boost::shared_ptr<LLNotificationForm> LLNotificationFormPtr;
typedef std::shared_ptr<LLNotificationForm> LLNotificationFormPtr;
// This is the class of object read from the XML file (notifications.xml,
// from the appropriate local language directory).

View File

@ -54,6 +54,10 @@ LLScrollListCell* LLScrollListCell::create(const LLScrollListCell::Params& cell_
{
cell = new LLScrollListIconText(cell_p);
}
else if (cell_p.type() == "bar")
{
cell = new LLScrollListBar(cell_p);
}
else // default is "text"
{
cell = new LLScrollListText(cell_p);
@ -165,6 +169,74 @@ void LLScrollListIcon::draw(const LLColor4& color, const LLColor4& highlight_col
}
}
//
// LLScrollListBar
//
LLScrollListBar::LLScrollListBar(const LLScrollListCell::Params& p)
: LLScrollListCell(p),
mRatio(0),
mColor(p.color),
mBottom(1),
mLeftPad(1),
mRightPad(1)
{}
LLScrollListBar::~LLScrollListBar()
{
}
/*virtual*/
S32 LLScrollListBar::getHeight() const
{
return LLScrollListCell::getHeight();
}
/*virtual*/
const LLSD LLScrollListBar::getValue() const
{
return LLStringUtil::null;
}
void LLScrollListBar::setValue(const LLSD& value)
{
if (value.has("ratio"))
{
mRatio = value["ratio"].asReal();
}
if (value.has("bottom"))
{
mBottom = value["bottom"].asInteger();
}
if (value.has("left_pad"))
{
mLeftPad = value["left_pad"].asInteger();
}
if (value.has("right_pad"))
{
mRightPad = value["right_pad"].asInteger();
}
}
void LLScrollListBar::setColor(const LLColor4& color)
{
mColor = color;
}
S32 LLScrollListBar::getWidth() const
{
return LLScrollListCell::getWidth();
}
void LLScrollListBar::draw(const LLColor4& color, const LLColor4& highlight_color) const
{
S32 bar_width = getWidth() - mLeftPad - mRightPad;
S32 left = bar_width - bar_width * mRatio;
left = llclamp(left, mLeftPad, getWidth() - mRightPad - 1);
gl_rect_2d(left, mBottom, getWidth() - mRightPad, mBottom - 1, mColor);
}
//
// LLScrollListText
//

View File

@ -33,6 +33,7 @@
#include "lluistring.h"
#include "v4color.h"
#include "llui.h"
#include "llgltexture.h"
class LLCheckBoxCtrl;
class LLSD;
@ -153,6 +154,7 @@ public:
void setText(const LLStringExplicit& text);
void setFontStyle(const U8 font_style);
void setAlignment(LLFontGL::HAlign align) { mFontAlignment = align; }
protected:
LLUIString mText;
@ -192,6 +194,26 @@ private:
LLFontGL::HAlign mAlignment;
};
class LLScrollListBar : public LLScrollListCell
{
public:
LLScrollListBar(const LLScrollListCell::Params& p);
/*virtual*/ ~LLScrollListBar();
/*virtual*/ void draw(const LLColor4& color, const LLColor4& highlight_color) const;
/*virtual*/ S32 getWidth() const;
/*virtual*/ S32 getHeight() const;
/*virtual*/ const LLSD getValue() const;
/*virtual*/ void setColor(const LLColor4&);
/*virtual*/ void setValue(const LLSD& value);
private:
LLColor4 mColor;
F32 mRatio;
S32 mBottom;
S32 mRightPad;
S32 mLeftPad;
};
/*
* An interactive cell containing a check box.
*/

View File

@ -3709,7 +3709,8 @@ BOOL LLScrollListCtrl::operateOnAll(EOperation op)
void LLScrollListCtrl::setFocus(BOOL b)
{
// for tabbing into pristine scroll lists (Finder)
if (!getFirstSelected())
//if (!getFirstSelected())
if (!getFirstSelected() && !getEnabled()) // <FS:LO> make disabled lists not jump to the top on clicking an element in them.
{
selectFirstItem();
//onCommit(); // SJB: selectFirstItem() will call onCommit() if appropriate

Some files were not shown because too many files have changed in this diff Show More