...
just like or , but that
+ # introduces an unnecessary extra level of nesting. Just skip.
+ pass
+ else:
+ # For any tag we don't recognize (notably | ), push a new, empty
+ # list to the top of the dest stack. This new list is NOT
+ # referenced by anything in self.table; thus, when we pop it, any
+ # data we've collected inside that list will be discarded.
+ self.dest.append([])
+
+ def handle_endtag(self, tag):
+ # Because we avoid pushing self.dest for in handle_starttag(), we
+ # must refrain from popping it for here.
+ if tag != "p":
+ # For everything else, including unrecognized tags, pop the dest
+ # stack, reverting to outer collection.
+ self.dest.pop()
+
+ def handle_startendtag(self, tag, attrs):
+ # The table of interest contains | entries of the form:
+ # 0x00000000 STATUS_SUCCESS
+ # The is very useful -- we definitely want two different data
+ # items for "0x00000000" and "STATUS_SUCCESS" -- but we don't need or
+ # want it to push, then discard, an empty list as it would if we let
+ # the default HTMLParser.handle_startendtag() call handle_starttag()
+ # followed by handle_endtag(). Just ignore or any other
+ # singleton tag.
+ pass
+
+ def handle_data(self, data):
+ # Outside the of interest, self.dest is empty. Do not bother
+ # collecting data when self.dest is empty.
+ # HTMLParser calls handle_data() with every chunk of whitespace
+ # between tags. That would be lovely if our eventual goal was to
+ # reconstitute the original input stream with its existing formatting,
+ # but for us, whitespace only clutters the table. Ignore it.
+ if self.dest and not self.whitespace.match(data):
+ # Here we're within our and we have non-whitespace data.
+ # Append it to the list designated by the top of the dest stack.
+ self.dest[-1].append(data)
+
+# cache for get_windows_table()
+_windows_table = None
+
+def get_windows_table():
+ global _windows_table
+ # If we already loaded _windows_table, no need to load it all over again.
+ if _windows_table:
+ return _windows_table
+
+ # windows-rcs.html was fetched on 2015-03-24 with the following command:
+ # curl -o windows-rcs.html \
+ # https://msdn.microsoft.com/en-us/library/cc704588.aspx
+ parser = TableParser()
+ with open(os.path.join(os.path.dirname(__file__), "windows-rcs.html")) as hf:
+ # We tried feeding the file data to TableParser in chunks, to avoid
+ # buffering the entire file as a single string. Unfortunately its
+ # handle_data() cannot tell the difference between distinct calls
+ # separated by HTML tags, and distinct calls necessitated by a chunk
+ # boundary. Sigh! Read in the whole file. At the time this was
+ # written, it was only 500KB anyway.
+ parser.feed(hf.read())
+ parser.close()
+ table = parser.table
+
+ # With our parser, any ... | row leaves a table entry
+ # consisting only of an empty list. Remove any such.
+ while table and not table[0]:
+ table.pop(0)
+
+ # We expect rows of the form:
+ # [['0x00000000', 'STATUS_SUCCESS'],
+ # ['The operation completed successfully.']]
+ # The latter list will have multiple entries if Microsoft embedded
+ # or ... in the text, in which case joining with '\n' is
+ # appropriate.
+ # Turn that into a dict whose key is the hex string, and whose value is
+ # the pair (symbol, desc).
+ _windows_table = dict((key, (symbol, '\n'.join(desc)))
+ for (key, symbol), desc in table)
+
+ return _windows_table
+
+log=logging.getLogger(__name__)
+logging.basicConfig()
+
+if __name__ == "__main__":
+ import argparse
+ parser = argparse.ArgumentParser()
+ parser.add_argument("-d", "--debug", dest="loglevel", action="store_const",
+ const=logging.DEBUG, default=logging.INFO)
+ parser.add_argument("-D", "--define", dest="vars", default=[], action="append",
+ metavar="VAR=value",
+ help="Add VAR=value to the env variables defined")
+ parser.add_argument("-l", "--libpath", dest="libpath", default=[], action="append",
+ metavar="DIR",
+ help="Add DIR to the platform-dependent DLL search path")
+ parser.add_argument("command")
+ parser.add_argument('args', nargs=argparse.REMAINDER)
+ args = parser.parse_args()
+
+ log.setLevel(args.loglevel)
+
+ # What we have in opts.vars is a list of strings of the form "VAR=value"
+ # or possibly just "VAR". What we want is a dict. We can build that dict by
+ # constructing a list of ["VAR", "value"] pairs -- so split each
+ # "VAR=value" string on the '=' sign (but only once, in case we have
+ # "VAR=some=user=string"). To handle the case of just "VAR", append "" to
+ # the list returned by split(), then slice off anything after the pair we
+ # want.
+ rc = main(command=args.command, arguments=args.args, libpath=args.libpath,
+ vars=dict([(pair.split('=', 1) + [""])[:2] for pair in args.vars]))
+ if rc not in (None, 0):
+ log.error("Failure running: %s" % " ".join([args.command] + args.args))
+ log.error("Error %s: %s" % (rc, translate_rc(rc)))
+ sys.exit((rc < 0) and 255 or rc)
diff --git a/indra/copy_win_scripts/start-client.py b/indra/copy_win_scripts/start-client.py
index 5f7ff2f293..63c765c2fa 100644
--- a/indra/copy_win_scripts/start-client.py
+++ b/indra/copy_win_scripts/start-client.py
@@ -1,4 +1,28 @@
-#!/usr/bin/env python
+#!/usr/bin/env python2
+"""\
+@file start-client.py
+
+$LicenseInfo:firstyear=2010&license=viewerlgpl$
+Second Life Viewer Source Code
+Copyright (C) 2010-2011, 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$
+"""
import sys, getopt
import os
import llstart
diff --git a/indra/deps/CMakeLists.txt b/indra/deps/CMakeLists.txt
new file mode 100644
index 0000000000..a8df464f19
--- /dev/null
+++ b/indra/deps/CMakeLists.txt
@@ -0,0 +1,62 @@
+project(deps)
+
+include(FetchContent)
+
+set(CMAKE_FOLDER "Third Party")
+set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+
+FetchContent_Declare(
+ Catch2
+ GIT_REPOSITORY https://github.com/catchorg/Catch2.git
+ GIT_TAG v2.11.0
+ GIT_SHALLOW TRUE
+ )
+FetchContent_Declare(
+ fmt
+ GIT_REPOSITORY https://github.com/fmtlib/fmt.git
+ GIT_TAG 8d78045e7cb44d39ad4cd95dd27816b8749e1944
+ )
+FetchContent_Declare(
+ nlohmann_json
+ GIT_REPOSITORY https://github.com/nlohmann/json.git
+ GIT_TAG v3.7.3
+ GIT_SHALLOW TRUE
+ )
+FetchContent_Declare(
+ absl
+ GIT_REPOSITORY https://github.com/abseil/abseil-cpp.git
+ GIT_TAG 768eb2ca2857342673fcd462792ce04b8bac3fa3
+)
+
+# This is a hack because absl has dumb cmake
+set(OLD_BUILD_TEST ${BUILD_TESTING})
+set(BUILD_TESTING OFF)
+FetchContent_MakeAvailable(absl)
+set(BUILD_TESTING ${OLD_BUILD_TEST})
+
+# Supress warnings inside abseil under MSVC
+if(WINDOWS)
+ target_compile_options(absl_strings PRIVATE /wd4018)
+ target_compile_options(absl_str_format_internal PRIVATE /wd4018)
+ target_compile_options(absl_flags_usage_internal PRIVATE /wd4018)
+endif()
+
+
+if (BUILD_TESTING)
+ FetchContent_MakeAvailable(Catch2)
+endif()
+
+#Download the rest of the libraries
+FetchContent_MakeAvailable(fmt)
+
+# Typically you don't care so much for a third party library's tests to be
+# run from your own project's code.
+set(JSON_BuildTests OFF CACHE INTERNAL "")
+
+# If you only include this third party in PRIVATE source files, you do not
+# need to install it when your main project gets installed.
+set(JSON_Install OFF CACHE INTERNAL "")
+FetchContent_MakeAvailable(nlohmann_json)
+
+unset(CMAKE_FOLDER)
+unset(CMAKE_POSITION_INDEPENDENT_CODE)
diff --git a/indra/develop.py b/indra/develop.py
deleted file mode 100755
index 018003c877..0000000000
--- a/indra/develop.py
+++ /dev/null
@@ -1,941 +0,0 @@
-#!/usr/bin/env python
-#
-# @file develop.py
-# @authors Bryan O'Sullivan, Mark Palange, Aaron Brashears
-# @brief Fire and forget script to appropriately configure cmake for SL.
-#
-# $LicenseInfo:firstyear=2007&license=viewergpl$
-#
-# Copyright (c) 2007-2009, Linden Research, Inc.
-#
-# Second Life Viewer Source Code
-# The source code in this file ("Source Code") is provided by Linden Lab
-# to you under the terms of the GNU General Public License, version 2.0
-# ("GPL"), unless you have obtained a separate licensing agreement
-# ("Other License"), formally executed by you and Linden Lab. Terms of
-# the GPL can be found in doc/GPL-license.txt in this distribution, or
-# online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
-#
-# There are special exceptions to the terms and conditions of the GPL as
-# it is applied to this Source Code. View the full text of the exception
-# in the file doc/FLOSS-exception.txt in this software distribution, or
-# online at
-# http://secondlifegrid.net/programs/open_source/licensing/flossexception
-#
-# By copying, modifying or distributing this software, you acknowledge
-# that you have read and understood your obligations described above,
-# and agree to abide by those obligations.
-#
-# ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
-# WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
-# COMPLETENESS OR PERFORMANCE.
-# $/LicenseInfo$
-
-
-import errno
-import getopt
-import os
-import random
-import re
-import shutil
-import socket
-import sys
-import commands
-import shlex
-
-class CommandError(Exception):
- pass
-
-def mkdir(path):
- try:
- os.mkdir(path)
- return path
- except OSError, err:
- if err.errno != errno.EEXIST or not os.path.isdir(path):
- raise
-
-def prettyprint_path_for_cmake(path):
- if 'a' <= path[0] <= 'z' and path[1] == ':':
- # CMake wants DOS drive letters to be in uppercase. The above
- # condition never asserts on platforms whose full path names
- # always begin with a slash, so we don't need to test whether
- # we are running on Windows.
- path = path[0].upper() + path[1:]
- return path
-
-def getcwd():
- return prettyprint_path_for_cmake(os.getcwd())
-
-source_indra = prettyprint_path_for_cmake(os.path.dirname(os.path.realpath(__file__)))
-
-def quote(opts):
- return '"' + '" "'.join([ opt.replace('"', '') for opt in opts ]) + '"'
-
-class PlatformSetup(object):
- generator = None
- build_types = {}
- for t in ('Debug', 'Release', 'RelWithDebInfo'):
- build_types[t.lower()] = t
-
- build_type = build_types['relwithdebinfo']
- standalone = 'OFF'
- unattended = 'OFF'
- universal = 'OFF'
- project_name = 'Singularity'
- distcc = True
- cmake_opts = []
- word_size = 32
- using_express = False
-
- def __init__(self):
- self.script_dir = os.path.realpath(
- os.path.dirname(__import__(__name__).__file__))
-
- def os(self):
- '''Return the name of the OS.'''
-
- raise NotImplemented('os')
-
- def arch(self):
- '''Return the CPU architecture.'''
-
- return None
-
- def platform(self):
- '''Return a stringified two-tuple of the OS name and CPU
- architecture.'''
-
- ret = self.os()
- if self.arch():
- ret += '-' + self.arch()
- return ret
-
- def build_dirs(self):
- '''Return the top-level directories in which builds occur.
- This can return more than one directory, e.g. if doing a
- 32-bit viewer and server build on Linux.'''
-
- if(os.path.basename(os.path.normpath(os.getcwd())) == 'indra'):
- prefix = '../'
- else:
- prefix = ''
-
- return [prefix+'build-' + self.platform()]
-
- def cmake_commandline(self, src_dir, build_dir, opts, simple):
- '''Return the command line to run cmake with.'''
-
- args = dict(
- dir=src_dir,
- generator=self.generator,
- opts=quote(opts),
- standalone=self.standalone,
- unattended=self.unattended,
- word_size=self.word_size,
- type=self.build_type.upper(),
- )
- #if simple:
- # return 'cmake %(opts)s %(dir)r' % args
- return ('cmake -DCMAKE_BUILD_TYPE:STRING=%(type)s '
- '-DSTANDALONE:BOOL=%(standalone)s '
- '-DUNATTENDED:BOOL=%(unattended)s '
- '-DWORD_SIZE:STRING=%(word_size)s '
- '-G %(generator)r %(opts)s %(dir)r' % args)
-
- def run_cmake(self, args=[]):
- '''Run cmake.'''
-
- # do a sanity check to make sure we have a generator
- if not hasattr(self, 'generator'):
- raise "No generator available for '%s'" % (self.__name__,)
- cwd = getcwd()
- created = []
- try:
- for d in self.build_dirs():
- simple = True
- if mkdir(d):
- created.append(d)
- simple = False
- try:
- os.chdir(d)
- cmd = self.cmake_commandline(source_indra, d, args, simple)
- print 'Running %r in %r' % (cmd, d)
- self.run(cmd, 'cmake')
- finally:
- os.chdir(cwd)
- except:
- # If we created a directory in which to run cmake and
- # something went wrong, the directory probably just
- # contains garbage, so delete it.
- os.chdir(cwd)
- for d in created:
- print 'Cleaning %r' % d
- shutil.rmtree(d)
- raise
-
- def parse_build_opts(self, arguments):
- opts, targets = getopt.getopt(arguments, 'D:o:', ['option='])
- build_opts = []
- for o, a in opts:
- if o in ('-o', '--option'):
- build_opts.append(a)
- return build_opts, targets
-
- def run_build(self, opts, targets):
- '''Build the default targets for this platform.'''
-
- raise NotImplemented('run_build')
-
- def cleanup(self):
- '''Delete all build directories.'''
-
- cleaned = 0
- for d in self.build_dirs():
- if os.path.isdir(d):
- print 'Cleaning %r' % d
- shutil.rmtree(d)
- cleaned += 1
- if not cleaned:
- print 'Nothing to clean up!'
-
- def is_internal_tree(self):
- '''Indicate whether we are building in an internal source tree.'''
-
- return os.path.isdir(os.path.join(self.script_dir, 'newsim'))
-
- def find_in_path(self, name, defval=None, basename=False):
- for ext in self.exe_suffixes:
- name_ext = name + ext
- if os.sep in name_ext:
- path = os.path.abspath(name_ext)
- if os.access(path, os.X_OK):
- return [basename and os.path.basename(path) or path]
- for p in os.getenv('PATH', self.search_path).split(os.pathsep):
- path = os.path.join(p, name_ext)
- if os.access(path, os.X_OK):
- return [basename and os.path.basename(path) or path]
- if defval:
- return [defval]
- return []
-
-
-class UnixSetup(PlatformSetup):
- '''Generic Unixy build instructions.'''
-
- search_path = '/usr/bin:/usr/local/bin'
- exe_suffixes = ('',)
-
- def __init__(self):
- PlatformSetup.__init__(self)
- super(UnixSetup, self).__init__()
- self.generator = 'Unix Makefiles'
-
- def os(self):
- return 'unix'
-
- def arch(self):
- cpu = os.uname()[-1]
- if cpu.endswith('386'):
- cpu = 'i386'
- elif cpu.endswith('86'):
- cpu = 'i686'
- elif cpu in ('athlon',):
- cpu = 'i686'
- elif cpu == 'Power Macintosh':
- cpu = 'ppc'
- elif cpu == 'x86_64' and self.word_size == 32:
- cpu = 'i686'
- return cpu
-
- def run(self, command, name=None):
- '''Run a program. If the program fails, raise an exception.'''
- ret = os.system(command)
- if ret:
- if name is None:
- name = command.split(None, 1)[0]
- if os.WIFEXITED(ret):
- st = os.WEXITSTATUS(ret)
- if st == 127:
- event = 'was not found'
- else:
- event = 'exited with status %d' % st
- elif os.WIFSIGNALED(ret):
- event = 'was killed by signal %d' % os.WTERMSIG(ret)
- else:
- event = 'died unexpectedly (!?) with 16-bit status %d' % ret
- raise CommandError('the command %r %s' %
- (name, event))
-
-
-class LinuxSetup(UnixSetup):
- def __init__(self):
- UnixSetup.__init__(self)
- super(LinuxSetup, self).__init__()
- try:
- self.debian_sarge = open('/etc/debian_version').read().strip() == '3.1'
- except:
- self.debian_sarge = False
-
- def os(self):
- return 'linux'
-
- def build_dirs(self):
- return [PlatformSetup.build_dirs(self)[0]+'-'+self.build_type.lower()]
-
- def cmake_commandline(self, src_dir, build_dir, opts, simple):
- args = dict(
- dir=src_dir,
- generator=self.generator,
- opts=quote(opts),
- standalone=self.standalone,
- unattended=self.unattended,
- type=self.build_type.upper(),
- project_name=self.project_name,
- word_size=self.word_size,
- cxx="g++"
- )
-
- cmd = (('cmake -DCMAKE_BUILD_TYPE:STRING=%(type)s '
- '-G %(generator)r -DSTANDALONE:BOOL=%(standalone)s '
- '-DWORD_SIZE:STRING=%(word_size)s '
- '-DROOT_PROJECT_NAME:STRING=%(project_name)s '
- '%(opts)s %(dir)r')
- % args)
- if 'CXX' not in os.environ:
- args.update({'cmd':cmd})
- cmd = ('CXX=%(cxx)r %(cmd)s' % args)
- return cmd
-
- def run_build(self, opts, targets):
- job_count = None
-
- for i in range(len(opts)):
- if opts[i].startswith('-j'):
- try:
- job_count = int(opts[i][2:])
- except ValueError:
- try:
- job_count = int(opts[i+1])
- except ValueError:
- job_count = True
-
- def get_cpu_count():
- count = 0
- for line in open('/proc/cpuinfo'):
- if re.match(r'processor\s*:', line):
- count += 1
- return count
-
- def localhost():
- count = get_cpu_count()
- return 'localhost/' + str(count), count
-
- def get_distcc_hosts():
- try:
- hosts = []
- name = os.getenv('DISTCC_DIR', '/etc/distcc') + '/hosts'
- for l in open(name):
- l = l[l.find('#')+1:].strip()
- if l: hosts.append(l)
- return hosts
- except IOError:
- return (os.getenv('DISTCC_HOSTS', '').split() or
- [localhost()[0]])
-
- def count_distcc_hosts():
- cpus = 0
- hosts = 0
- for host in get_distcc_hosts():
- m = re.match(r'.*/(\d+)', host)
- hosts += 1
- cpus += m and int(m.group(1)) or 1
- return hosts, cpus
-
- def mk_distcc_hosts(basename, range, num_cpus):
- '''Generate a list of LL-internal machines to build on.'''
- loc_entry, cpus = localhost()
- hosts = [loc_entry]
- dead = []
- stations = [s for s in xrange(range) if s not in dead]
- random.shuffle(stations)
- hosts += ['%s%d.lindenlab.com/%d,lzo' % (basename, s, num_cpus) for s in stations]
- cpus += 2 * len(stations)
- return ' '.join(hosts), cpus
-
- if job_count is None:
- hosts, job_count = count_distcc_hosts()
- if hosts == 1:
- hostname = socket.gethostname()
- if hostname.startswith('station'):
- hosts, job_count = mk_distcc_hosts('station', 36, 2)
- os.environ['DISTCC_HOSTS'] = hosts
- if hostname.startswith('eniac'):
- hosts, job_count = mk_distcc_hosts('eniac', 71, 2)
- os.environ['DISTCC_HOSTS'] = hosts
- if job_count > 4:
- job_count = 4;
- opts.extend(['-j', str(job_count)])
-
- if targets:
- targets = ' '.join(targets)
- else:
- targets = 'all'
-
- for d in self.build_dirs():
- cmd = 'make -C %r %s %s' % (d, ' '.join(opts), targets)
- print 'Running %r' % cmd
- self.run(cmd)
-
-
-class DarwinSetup(UnixSetup):
- def __init__(self):
- UnixSetup.__init__(self)
- super(DarwinSetup, self).__init__()
- self.generator = 'Xcode'
-
- def os(self):
- return 'darwin'
-
- def arch(self):
- if self.universal == 'ON':
- return 'universal'
- else:
- return UnixSetup.arch(self)
-
- def build_dirs(self):
- if(self.generator == 'Xcode'):
- return PlatformSetup.build_dirs(self)
- else:
- return [PlatformSetup.build_dirs(self)[0]+'-'+self.build_type.lower()]
-
- def cmake_commandline(self, src_dir, build_dir, opts, simple):
- args = dict(
- dir=src_dir,
- generator=self.generator,
- opts=quote(opts),
- standalone=self.standalone,
- word_size=self.word_size,
- unattended=self.unattended,
- project_name=self.project_name,
- universal='',
- type='',
- )
- if(self.generator != 'Xcode'):
- args['type'] = '-DCMAKE_BUILD_TYPE=%s' % self.build_type.upper()
- if self.universal == 'ON':
- args['universal'] = '-DCMAKE_OSX_ARCHITECTURES:STRING=\'i386;ppc\''
- #if simple:
- # return 'cmake %(opts)s %(dir)r' % args
- return ('cmake -G %(generator)r '
- '%(type)s '
- '-DSTANDALONE:BOOL=%(standalone)s '
- '-DUNATTENDED:BOOL=%(unattended)s '
- '-DWORD_SIZE:STRING=%(word_size)s '
- '-DROOT_PROJECT_NAME:STRING=%(project_name)s '
- '%(universal)s '
- '%(opts)s %(dir)r' % args)
-
- def run_build(self, opts, targets):
- if(self.generator != 'Xcode'):
- if targets:
- targets = ' '.join(targets)
- else:
- targets = 'all'
-
- for d in self.build_dirs():
- cmd = 'make -C %r %s %s' % (d, ' '.join(opts), targets)
- print 'Running %r' % cmd
- self.run(cmd)
- return
-
- cwd = getcwd()
- if targets:
- targets = ' '.join(['-target ' + repr(t) for t in targets])
- else:
- targets = ''
- cmd = ('xcodebuild -configuration %s %s %s' %
- (self.build_type, ' '.join(opts), targets))
- for d in self.build_dirs():
- try:
- os.chdir(d)
- print 'Running %r in %r' % (cmd, d)
- self.run(cmd)
- finally:
- os.chdir(cwd)
-
-
-class WindowsSetup(PlatformSetup):
- gens = {
- 'vc100' : {
- 'gen' : r'Visual Studio 10',
- 'ver' : r'10.0'
- },
- 'vc120' : {
- 'gen' : r'Visual Studio 12',
- 'ver' : r'12.0'
- }
- }
-
- gens['vs2010'] = gens['vc100']
- gens['vs2013'] = gens['vc120']
-
- search_path = r'C:\windows'
- exe_suffixes = ('.exe', '.bat', '.com')
-
- def __init__(self):
- PlatformSetup.__init__(self)
- super(WindowsSetup, self).__init__()
- self._generator = None
- self.incredibuild = False
-
- def _get_generator(self):
- if self._generator is None:
- for version in 'vc100'.split():
- if self.find_visual_studio(version):
- self._generator = version
- print 'Building with ', self.gens[version]['gen']
- break
- else:
- print >> sys.stderr, 'Cannot find a Visual Studio installation, testing for express editions'
- for version in 'vc100'.split():
- if self.find_visual_studio_express(version):
- self._generator = version
- self.using_express = True
- print 'Building with ', self.gens[version]['gen'] , "Express edition"
- break
- else:
- for version in 'vc100'.split():
- if self.find_visual_studio_express_single(version):
- self._generator = version
- self.using_express = True
- print 'Building with ', self.gens[version]['gen'] , "Express edition"
- break
- else:
- print >> sys.stderr, 'Cannot find any Visual Studio installation'
- sys.exit(1)
- return self._generator
-
- def _set_generator(self, gen):
- self._generator = gen
-
- generator = property(_get_generator, _set_generator)
-
- def get_gen_str(self, gen):
- if gen is None:
- gen = self._generator
- return self.gens[gen.lower()]['ver']
-
- def os(self):
- return 'win32'
-
- def build_dirs(self):
- if(os.path.basename(os.path.normpath(os.getcwd())) == 'indra'):
- prefix = '../'
- else:
- prefix = ''
-
- if self.word_size == 64:
- return [prefix+'build-' + self.generator + '-Win64']
- else:
- return [prefix+'build-' + self.generator]
-
- def cmake_commandline(self, src_dir, build_dir, opts, simple):
- args = dict(
- dir=src_dir,
- generator=self.gens[self.generator.lower()]['gen'],
- opts=quote(opts),
- standalone=self.standalone,
- unattended=self.unattended,
- project_name=self.project_name,
- word_size=self.word_size,
- )
- if self.word_size == 64:
- args["generator"] += r' Win64'
-
- #if simple:
- # return 'cmake %(opts)s "%(dir)s"' % args
- return ('cmake -G "%(generator)s" '
- '-DSTANDALONE:BOOL=%(standalone)s '
- '-DUNATTENDED:BOOL=%(unattended)s '
- '-DWORD_SIZE:STRING=%(word_size)s '
- '-DROOT_PROJECT_NAME:STRING=\"%(project_name)s\" '
- '%(opts)s "%(dir)s"' % args)
-
- def get_HKLM_registry_value(self, key_str, value_str):
- import _winreg
- reg = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE)
- key = _winreg.OpenKey(reg, key_str)
- value = _winreg.QueryValueEx(key, value_str)[0]
- print 'Found: %s' % value
- return value
-
- def find_visual_studio(self, gen=None):
- gen = self.get_gen_str(gen)
- value_str = (r'EnvironmentDirectory')
- key_str = (r'SOFTWARE\Microsoft\VisualStudio\%s\Setup\VS' %
- gen)
- print ('Reading VS environment from HKEY_LOCAL_MACHINE\%s\%s' %
- (key_str, value_str))
- try:
- return self.get_HKLM_registry_value(key_str, value_str)
- except WindowsError, err:
- key_str = (r'SOFTWARE\Wow6432Node\Microsoft\VisualStudio\%s\Setup\VS' %
- gen)
-
- try:
- return self.get_HKLM_registry_value(key_str, value_str)
- except:
- print >> sys.stderr, "Didn't find ", self.gens[gen]['gen']
- return ''
-
- def find_msbuild(self, gen=None):
- gen = self.get_gen_str(gen)
-
- key_str = (r'SOFTWARE\Microsoft\MSBuild\ToolsVersions\12.0')
-
- print ('Checking MSBuild support for vs ver = %s' % gen)
- if not self.get_HKLM_registry_value(key_str+'\\'+gen, "VCTargetsPath"):
- return (None, None)
- print ('Reading MSBuild location from HKEY_LOCAL_MACHINE\%s\MSBuildToolsPath' %
- key_str)
- print key_str
- try:
- return (self.get_HKLM_registry_value(key_str, 'MSBuildToolsPath'), gen)
- except WindowsError, err:
- key_str = (r'SOFTWARE\Wow6432Node\Microsoft\MSBuild\ToolsVersions\%s' %
- gen)
-
- try:
- return (self.get_HKLM_registry_value(key_str, 'MSBuildToolsPath'), gen)
- except WindowsError, err:
- print 'Didn\'t find msbuild'
- return (None, None)
-
- def find_visual_studio_express(self, gen=None):
- gen = self.get_gen_str(gen)
- try:
- import _winreg
- key_str = (r'SOFTWARE\Microsoft\VCEXpress\%s\Setup\VC' %
- gen)
- value_str = (r'ProductDir')
- print ('Reading VS environment from HKEY_LOCAL_MACHINE\%s\%s' %
- (key_str, value_str))
- print key_str
-
- reg = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE)
- key = _winreg.OpenKey(reg, key_str)
- value = _winreg.QueryValueEx(key, value_str)[0]+"IDE"
- print 'Found: %s' % value
- return value
- except WindowsError, err:
- print >> sys.stderr, "Didn't find ", gen
- return ''
-
- def find_visual_studio_express_single(self, gen=None):
- gen = self.get_gen_str(gen)
- try:
- import _winreg
- key_str = (r'SOFTWARE\Microsoft\VCEXpress\%s_Config\Setup\VC' %
- gen)
- value_str = (r'ProductDir')
- print ('Reading VS environment from HKEY_CURRENT_USER\%s\%s' %
- (key_str, value_str))
- print key_str
-
- reg = _winreg.ConnectRegistry(None, _winreg.HKEY_CURRENT_USER)
- key = _winreg.OpenKey(reg, key_str)
- value = _winreg.QueryValueEx(key, value_str)[0]+"IDE"
- print 'Found: %s' % value
- return value
- except WindowsError, err:
- print >> sys.stderr, "Didn't find ", gen
- return ''
-
- def get_build_cmd(self):
- if self.incredibuild:
- config = self.build_type
- if self.gens[self.generator]['ver'] in [ r'8.0', r'9.0' ]:
- config = '\"%s|Win32\"' % config
-
- return "buildconsole \"%s.sln\" /build %s" % (self.project_name, config), None
- environment = self.find_visual_studio()
- if environment == '':
- environment = self.find_visual_studio_express()
- if environment == '':
- environment = self.find_visual_studio_express_single()
- if environment == '':
- print >> sys.stderr, "Something went very wrong during build stage, could not find a Visual Studio?"
- else:
- build_dirs=self.build_dirs()
- print >> sys.stderr, "\nSolution generation complete, it can can now be found in:", build_dirs[0]
- print >> sys.stderr, "\nAs you are using an Express Visual Studio, the build step cannot be automated"
- print >> sys.stderr, "\nPlease see https://wiki.secondlife.com/wiki/Microsoft_Visual_Studio#Extra_steps_for_Visual_Studio_Express_editions for Visual Studio Express specific information"
- exit(0)
-
- msbuild_dir, tool_ver = self.find_msbuild()
-
- if msbuild_dir is not None and tool_ver is not None:
- return ('\"%smsbuild.exe\" \"%s.sln\" /p:configuration=%s /p:VisualStudioVersion=%s' %
- (msbuild_dir, self.project_name, self.build_type, tool_ver)), True
-
- # devenv.com is CLI friendly, devenv.exe... not so much.
- return ('"%sdevenv.com" \"%s.sln\" /build %s' %
- (self.find_visual_studio(), self.project_name, self.build_type)), None
-
- def run(self, command, name=None):
- '''Run a program. If the program fails, raise an exception.'''
- ret = os.system('\"'+command+'\"')
- if ret:
- if name is None:
- name = os.path.normpath(shlex.split(command.encode('utf8'),posix=False)[0].strip('"'))
-
- path = self.find_in_path(name)
- if not path:
- ret = 'was not found'
- else:
- ret = 'exited with status %d' % ret
- raise CommandError('the command %r %s' %
- (name, ret))
-
- def run_cmake(self, args=[]):
- '''Override to add the vstool.exe call after running cmake.'''
- PlatformSetup.run_cmake(self, args)
- if self.unattended == 'OFF':
- if self.using_express == False:
- self.run_vstool()
-
- def run_vstool(self):
- for build_dir in self.build_dirs():
- stamp = os.path.join(build_dir, 'vstool.txt')
- try:
- prev_build = open(stamp).read().strip()
- except IOError:
- prev_build = ''
- if prev_build == self.build_type:
- # Only run vstool if the build type has changed.
- continue
-
- if(os.path.basename(os.path.normpath(os.getcwd())) == 'indra'):
- tool_path = os.path.join('tools','vstool','VSTool.exe')
- else:
- tool_path = os.path.join('indra','tools','vstool','VSTool.exe')
- vstool_cmd = (tool_path +
- ' --solution \"' +
- os.path.join(build_dir,'%s.sln' % self.project_name) +
- '\" --config ' + self.build_type +
- ' --startup secondlife-bin')
- print 'Running vstool %r in %r' % (vstool_cmd, getcwd())
- self.run(vstool_cmd)
- print >> open(stamp, 'w'), self.build_type
-
- def run_build(self, opts, targets):
- cwd = getcwd()
- build_cmd, msbuild = self.get_build_cmd()
-
- for d in self.build_dirs():
- try:
- os.chdir(d)
- if targets:
- if msbuild:
- cmd = '%s /target:%s %s' % (build_cmd, ';'.join(targets), ' '.join(opts))
- print 'Running build(targets) %r in %r' % (cmd, d)
- self.run(cmd)
- else:
- for t in targets:
- cmd = '%s /project %s %s' % (build_cmd, t, ' '.join(opts))
- print 'Running build(targets) %r in %r' % (cmd, d)
- self.run(cmd)
- else:
- cmd = '%s %s' % (build_cmd, ' '.join(opts))
- print 'Running build %r in %r' % (cmd, d)
- self.run(cmd)
- finally:
- os.chdir(cwd)
-
-class CygwinSetup(WindowsSetup):
- def __init__(self):
- super(CygwinSetup, self).__init__()
- self.generator = 'vc80'
-
- def cmake_commandline(self, src_dir, build_dir, opts, simple):
- dos_dir = commands.getoutput("cygpath -w %s" % src_dir)
- args = dict(
- dir=dos_dir,
- generator=self.gens[self.generator.lower()]['gen'],
- opts=quote(opts),
- standalone=self.standalone,
- unattended=self.unattended,
- project_name=self.project_name,
- word_size=self.word_size,
- )
- if self.word_size == 64:
- args["generator"] += r' Win64'
- #if simple:
- # return 'cmake %(opts)s "%(dir)s"' % args
- return ('cmake -G "%(generator)s" '
- '-DUNATTENDED:BOOl=%(unattended)s '
- '-DSTANDALONE:BOOL=%(standalone)s '
- '-DWORD_SIZE:STRING=%(word_size)s '
- '-DROOT_PROJECT_NAME:STRING=%(project_name)s '
- '%(opts)s "%(dir)s"' % args)
-
- def run(self, command, name=None):
- '''Run a program. If the program fails, raise an exception.'''
- ret = os.system(command)
- if ret:
- if name is None:
- name = os.path.normpath(shlex.split(command.encode('utf8'),posix=False)[0].strip('"'))
-
- path = self.find_in_path(name)
- if not path:
- ret = 'was not found'
- else:
- ret = 'exited with status %d' % ret
- raise CommandError('the command %r %s' %
- (name, ret))
-
-
-setup_platform = {
- 'darwin': DarwinSetup,
- 'linux2': LinuxSetup,
- 'linux3': LinuxSetup,
- 'win32' : WindowsSetup,
- 'cygwin' : CygwinSetup
- }
-
-
-usage_msg = '''
-Usage: develop.py [options] [command [command-options]]
-
-Options:
- -h | --help print this help message
- --standalone build standalone, without Linden prebuild libraries
- --unattended build unattended, do not invoke any tools requiring
- a human response
- --universal build a universal binary on Mac OS X (unsupported)
- -t | --type=NAME build type ("Debug", "Release", or "RelWithDebInfo")
- -m32 | -m64 build architecture (32-bit or 64-bit)
- -N | --no-distcc disable use of distcc
- -G | --generator=NAME generator name
- Windows: VC100 (VS2010) (default)
- Mac OS X: Xcode (default), Unix Makefiles
- Linux: Unix Makefiles (default), KDevelop3
- -p | --project=NAME set the root project name. (Doesn't effect makefiles)
-
-Commands:
- build configure and build default target
- clean delete all build directories, does not affect sources
- configure configure project by running cmake (default if none given)
- printbuilddirs print the build directory that will be used
-
-Command-options for "configure":
- We use cmake variables to change the build configuration.
- -DPACKAGE:BOOL=ON Create "package" target to make installers
- -DLL_TESTS:BOOL=OFF Don't generate unit test projects
- -DEXAMPLEPLUGIN:BOOL=OFF Don't generate example plugin project
- -DDISABLE_TCMALLOC:BOOL=ON Disable linkage of TCMalloc. (64bit builds automatically disable TCMalloc)
- -DRELEASE_CRASH_REPORTING:BOOL=ON Enable Google Breakpad crash reporting
- -DFMODSTUDIO:BOOL=ON Use FMOD Studio audio libraries
- -DFMODEX:BOOL=ON Use FMOD Ex audio libraries
-
-Examples:
- Set up a Visual Studio 2010 project with "package" target:
- develop.py -G vc100 configure -DPACKAGE:BOOL=ON
-'''
-
-def main(arguments):
- setup = setup_platform[sys.platform]()
- try:
- opts, args = getopt.getopt(
- arguments,
- '?hNt:p:G:m:',
- ['help', 'standalone', 'no-distcc', 'unattended', 'type=', 'incredibuild', 'generator=', 'project='])
- except getopt.GetoptError, err:
- print >> sys.stderr, 'Error:', err
- print >> sys.stderr, """
-Note: You must pass -D options to cmake after the "configure" command
-For example: develop.py configure -DSERVER:BOOL=OFF"""
- print >> sys.stderr, usage_msg.strip()
- sys.exit(1)
-
- for o, a in opts:
- if o in ('-?', '-h', '--help'):
- print usage_msg.strip()
- sys.exit(0)
- elif o in ('--standalone',):
- setup.standalone = 'ON'
- elif o in ('--unattended',):
- setup.unattended = 'ON'
- elif o in ('-m',):
- if a in ('32', '64'):
- setup.word_size = int(a)
- else:
- print >> sys.stderr, 'Error: unknown word size', repr(a)
- print >> sys.stderr, 'Supported word sizes: 32, 64'
- sys.exit(1)
- elif o in ('-t', '--type'):
- try:
- setup.build_type = setup.build_types[a.lower()]
- except KeyError:
- print >> sys.stderr, 'Error: unknown build type', repr(a)
- print >> sys.stderr, 'Supported build types:'
- types = setup.build_types.values()
- types.sort()
- for t in types:
- print ' ', t
- sys.exit(1)
- elif o in ('-G', '--generator'):
- setup.generator = a
- elif o in ('-N', '--no-distcc'):
- setup.distcc = False
- elif o in ('-p', '--project'):
- setup.project_name = a
- elif o in ('--incredibuild'):
- setup.incredibuild = True
- else:
- print >> sys.stderr, 'INTERNAL ERROR: unhandled option', repr(o)
- sys.exit(1)
- if not args:
- setup.run_cmake()
- return
- try:
- cmd = args.pop(0)
- if cmd in ('cmake', 'configure'):
- setup.run_cmake(args)
- elif cmd == 'build':
- if os.getenv('DISTCC_DIR') is None:
- distcc_dir = os.path.join(getcwd(), '.distcc')
- if not os.path.exists(distcc_dir):
- os.mkdir(distcc_dir)
- print "setting DISTCC_DIR to %s" % distcc_dir
- os.environ['DISTCC_DIR'] = distcc_dir
- else:
- print "DISTCC_DIR is set to %s" % os.getenv('DISTCC_DIR')
- for d in setup.build_dirs():
- if not os.path.exists(d):
- raise CommandError('run "develop.py cmake" first')
- setup.run_cmake()
- opts, targets = setup.parse_build_opts(args)
- setup.run_build(opts, targets)
- elif cmd == 'clean':
- if args:
- raise CommandError('clean takes no arguments')
- setup.cleanup()
- elif cmd == 'printbuilddirs':
- for d in setup.build_dirs():
- print >> sys.stdout, d
- else:
- print >> sys.stderr, 'Error: unknown subcommand', repr(cmd)
- print >> sys.stderr, "(run 'develop.py --help' for help)"
- sys.exit(1)
- except getopt.GetoptError, err:
- print >> sys.stderr, 'Error with %r subcommand: %s' % (cmd, err)
- sys.exit(1)
-
-
-if __name__ == '__main__':
- try:
- main(sys.argv[1:])
- except CommandError, err:
- print >> sys.stderr, 'Error:', err
- sys.exit(1)
diff --git a/indra/lib/python/indra/base/__init__.py b/indra/lib/python/indra/base/__init__.py
deleted file mode 100644
index 2904fd3380..0000000000
--- a/indra/lib/python/indra/base/__init__.py
+++ /dev/null
@@ -1,27 +0,0 @@
-"""\
-@file __init__.py
-@brief Initialization file for the indra.base module.
-
-$LicenseInfo:firstyear=2007&license=mit$
-
-Copyright (c) 2007-2009, Linden Research, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-$/LicenseInfo$
-"""
diff --git a/indra/lib/python/indra/base/cllsd_test.py b/indra/lib/python/indra/base/cllsd_test.py
deleted file mode 100644
index 1f06898ffd..0000000000
--- a/indra/lib/python/indra/base/cllsd_test.py
+++ /dev/null
@@ -1,73 +0,0 @@
-#!/usr/bin/python
-##
-## $LicenseInfo:firstyear=2011&license=viewerlgpl$
-## Second Life Viewer Source Code
-## Copyright (C) 2011, 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$
-from indra.base import llsd, lluuid
-from datetime import datetime
-import cllsd
-import time, sys
-
-class myint(int):
- pass
-
-values = (
- '&<>',
- u'\u81acj',
- llsd.uri('http://foo<'),
- lluuid.UUID(),
- llsd.LLSD(['thing']),
- 1,
- myint(31337),
- sys.maxint + 10,
- llsd.binary('foo'),
- [],
- {},
- {u'f&\u1212': 3},
- 3.1,
- True,
- None,
- datetime.fromtimestamp(time.time()),
- )
-
-def valuator(values):
- for v in values:
- yield v
-
-longvalues = () # (values, list(values), iter(values), valuator(values))
-
-for v in values + longvalues:
- print '%r => %r' % (v, cllsd.llsd_to_xml(v))
-
-a = [[{'a':3}]] * 1000000
-
-s = time.time()
-print hash(cllsd.llsd_to_xml(a))
-e = time.time()
-t1 = e - s
-print t1
-
-s = time.time()
-print hash(llsd.LLSDXMLFormatter()._format(a))
-e = time.time()
-t2 = e - s
-print t2
-
-print 'Speedup:', t2 / t1
diff --git a/indra/lib/python/indra/base/config.py b/indra/lib/python/indra/base/config.py
deleted file mode 100644
index adafa29b51..0000000000
--- a/indra/lib/python/indra/base/config.py
+++ /dev/null
@@ -1,266 +0,0 @@
-"""\
-@file config.py
-@brief Utility module for parsing and accessing the indra.xml config file.
-
-$LicenseInfo:firstyear=2006&license=mit$
-
-Copyright (c) 2006-2009, Linden Research, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-$/LicenseInfo$
-"""
-
-import copy
-import errno
-import os
-import traceback
-import time
-import types
-
-from os.path import dirname, getmtime, join, realpath
-from indra.base import llsd
-
-_g_config = None
-
-class IndraConfig(object):
- """
- IndraConfig loads a 'indra' xml configuration file
- and loads into memory. This representation in memory
- can get updated to overwrite values or add new values.
-
- The xml configuration file is considered a live file and changes
- to the file are checked and reloaded periodically. If a value had
- been overwritten via the update or set method, the loaded values
- from the file are ignored (the values from the update/set methods
- override)
- """
- def __init__(self, indra_config_file):
- self._indra_config_file = indra_config_file
- self._reload_check_interval = 30 # seconds
- self._last_check_time = 0
- self._last_mod_time = 0
-
- self._config_overrides = {}
- self._config_file_dict = {}
- self._combined_dict = {}
-
- self._load()
-
- def _load(self):
- # if you initialize the IndraConfig with None, no attempt
- # is made to load any files
- if self._indra_config_file is None:
- return
-
- config_file = open(self._indra_config_file)
- self._config_file_dict = llsd.parse(config_file.read())
- self._combine_dictionaries()
- config_file.close()
-
- self._last_mod_time = self._get_last_modified_time()
- self._last_check_time = time.time() # now
-
- def _get_last_modified_time(self):
- """
- Returns the mtime (last modified time) of the config file,
- if such exists.
- """
- if self._indra_config_file is not None:
- return os.path.getmtime(self._indra_config_file)
-
- return 0
-
- def _combine_dictionaries(self):
- self._combined_dict = {}
- self._combined_dict.update(self._config_file_dict)
- self._combined_dict.update(self._config_overrides)
-
- def _reload_if_necessary(self):
- now = time.time()
-
- if (now - self._last_check_time) > self._reload_check_interval:
- self._last_check_time = now
- try:
- modtime = self._get_last_modified_time()
- if modtime > self._last_mod_time:
- self._load()
- except OSError, e:
- if e.errno == errno.ENOENT: # file not found
- # someone messed with our internal state
- # or removed the file
-
- print 'WARNING: Configuration file has been removed ' + (self._indra_config_file)
- print 'Disabling reloading of configuration file.'
-
- traceback.print_exc()
-
- self._indra_config_file = None
- self._last_check_time = 0
- self._last_mod_time = 0
- else:
- raise # pass the exception along to the caller
-
- def __getitem__(self, key):
- self._reload_if_necessary()
-
- return self._combined_dict[key]
-
- def get(self, key, default = None):
- try:
- return self.__getitem__(key)
- except KeyError:
- return default
-
- def __setitem__(self, key, value):
- """
- Sets the value of the config setting of key to be newval
-
- Once any key/value pair is changed via the set method,
- that key/value pair will remain set with that value until
- change via the update or set method
- """
- self._config_overrides[key] = value
- self._combine_dictionaries()
-
- def set(self, key, newval):
- return self.__setitem__(key, newval)
-
- def update(self, new_conf):
- """
- Load an XML file and apply its map as overrides or additions
- to the existing config. Update can be a file or a dict.
-
- Once any key/value pair is changed via the update method,
- that key/value pair will remain set with that value until
- change via the update or set method
- """
- if isinstance(new_conf, dict):
- overrides = new_conf
- else:
- # assuming that it is a filename
- config_file = open(new_conf)
- overrides = llsd.parse(config_file.read())
- config_file.close()
-
- self._config_overrides.update(overrides)
- self._combine_dictionaries()
-
- def as_dict(self):
- """
- Returns immutable copy of the IndraConfig as a dictionary
- """
- return copy.deepcopy(self._combined_dict)
-
-def load(config_xml_file = None):
- global _g_config
-
- load_default_files = config_xml_file is None
- if load_default_files:
- ## going from:
- ## "/opt/linden/indra/lib/python/indra/base/config.py"
- ## to:
- ## "/opt/linden/etc/indra.xml"
- config_xml_file = realpath(
- dirname(realpath(__file__)) + "../../../../../../etc/indra.xml")
-
- try:
- _g_config = IndraConfig(config_xml_file)
- except IOError:
- # Failure to load passed in file
- # or indra.xml default file
- if load_default_files:
- try:
- config_xml_file = realpath(
- dirname(realpath(__file__)) + "../../../../../../etc/globals.xml")
- _g_config = IndraConfig(config_xml_file)
- return
- except IOError:
- # Failure to load globals.xml
- # fall to code below
- pass
-
- # Either failed to load passed in file
- # or failed to load all default files
- _g_config = IndraConfig(None)
-
-def dump(indra_xml_file, indra_cfg = None, update_in_mem=False):
- '''
- Dump config contents into a file
- Kindof reverse of load.
- Optionally takes a new config to dump.
- Does NOT update global config unless requested.
- '''
- global _g_config
-
- if not indra_cfg:
- if _g_config is None:
- return
-
- indra_cfg = _g_config.as_dict()
-
- if not indra_cfg:
- return
-
- config_file = open(indra_xml_file, 'w')
- _config_xml = llsd.format_xml(indra_cfg)
- config_file.write(_config_xml)
- config_file.close()
-
- if update_in_mem:
- update(indra_cfg)
-
-def update(new_conf):
- global _g_config
-
- if _g_config is None:
- # To keep with how this function behaved
- # previously, a call to update
- # before the global is defined
- # make a new global config which does not
- # load data from a file.
- _g_config = IndraConfig(None)
-
- return _g_config.update(new_conf)
-
-def get(key, default = None):
- global _g_config
-
- if _g_config is None:
- load()
-
- return _g_config.get(key, default)
-
-def set(key, newval):
- """
- Sets the value of the config setting of key to be newval
-
- Once any key/value pair is changed via the set method,
- that key/value pair will remain set with that value until
- change via the update or set method or program termination
- """
- global _g_config
-
- if _g_config is None:
- _g_config = IndraConfig(None)
-
- _g_config.set(key, newval)
-
-def get_config():
- global _g_config
- return _g_config
diff --git a/indra/lib/python/indra/base/llsd.py b/indra/lib/python/indra/base/llsd.py
deleted file mode 100644
index 4527b115f9..0000000000
--- a/indra/lib/python/indra/base/llsd.py
+++ /dev/null
@@ -1,1052 +0,0 @@
-"""\
-@file llsd.py
-@brief Types as well as parsing and formatting functions for handling LLSD.
-
-$LicenseInfo:firstyear=2006&license=mit$
-
-Copyright (c) 2006-2009, Linden Research, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-$/LicenseInfo$
-"""
-
-import datetime
-import base64
-import string
-import struct
-import time
-import types
-import re
-
-from indra.util.fastest_elementtree import ElementTreeError, fromstring
-from indra.base import lluuid
-
-# cllsd.c in server/server-1.25 has memory leaks,
-# so disabling cllsd for now
-#try:
-# import cllsd
-#except ImportError:
-# cllsd = None
-cllsd = None
-
-int_regex = re.compile(r"[-+]?\d+")
-real_regex = re.compile(r"[-+]?(\d+(\.\d*)?|\d*\.\d+)([eE][-+]?\d+)?")
-alpha_regex = re.compile(r"[a-zA-Z]+")
-date_regex = re.compile(r"(?P\d{4})-(?P\d{2})-(?P\d{2})T"
- r"(?P\d{2}):(?P\d{2}):(?P\d{2})"
- r"(?P(\.\d+)?)Z")
-#date: d"YYYY-MM-DDTHH:MM:SS.FFFFFFZ"
-
-class LLSDParseError(Exception):
- pass
-
-class LLSDSerializationError(TypeError):
- pass
-
-
-class binary(str):
- pass
-
-class uri(str):
- pass
-
-
-BOOL_TRUE = ('1', '1.0', 'true')
-BOOL_FALSE = ('0', '0.0', 'false', '')
-
-
-def format_datestr(v):
- """ Formats a datetime or date object into the string format shared by xml and notation serializations."""
- if hasattr(v, 'microsecond'):
- return v.isoformat() + 'Z'
- else:
- return v.strftime('%Y-%m-%dT%H:%M:%SZ')
-
-def parse_datestr(datestr):
- """Parses a datetime object from the string format shared by xml and notation serializations."""
- if datestr == "":
- return datetime.datetime(1970, 1, 1)
-
- match = re.match(date_regex, datestr)
- if not match:
- raise LLSDParseError("invalid date string '%s'." % datestr)
-
- year = int(match.group('year'))
- month = int(match.group('month'))
- day = int(match.group('day'))
- hour = int(match.group('hour'))
- minute = int(match.group('minute'))
- second = int(match.group('second'))
- seconds_float = match.group('second_float')
- microsecond = 0
- if seconds_float:
- microsecond = int(float('0' + seconds_float) * 1e6)
- return datetime.datetime(year, month, day, hour, minute, second, microsecond)
-
-
-def bool_to_python(node):
- val = node.text or ''
- if val in BOOL_TRUE:
- return True
- else:
- return False
-
-def int_to_python(node):
- val = node.text or ''
- if not val.strip():
- return 0
- return int(val)
-
-def real_to_python(node):
- val = node.text or ''
- if not val.strip():
- return 0.0
- return float(val)
-
-def uuid_to_python(node):
- return lluuid.UUID(node.text)
-
-def str_to_python(node):
- return node.text or ''
-
-def bin_to_python(node):
- return binary(base64.decodestring(node.text or ''))
-
-def date_to_python(node):
- val = node.text or ''
- if not val:
- val = "1970-01-01T00:00:00Z"
- return parse_datestr(val)
-
-
-def uri_to_python(node):
- val = node.text or ''
- if not val:
- return None
- return uri(val)
-
-def map_to_python(node):
- result = {}
- for index in range(len(node))[::2]:
- result[node[index].text] = to_python(node[index+1])
- return result
-
-def array_to_python(node):
- return [to_python(child) for child in node]
-
-
-NODE_HANDLERS = dict(
- undef=lambda x: None,
- boolean=bool_to_python,
- integer=int_to_python,
- real=real_to_python,
- uuid=uuid_to_python,
- string=str_to_python,
- binary=bin_to_python,
- date=date_to_python,
- uri=uri_to_python,
- map=map_to_python,
- array=array_to_python,
- )
-
-def to_python(node):
- return NODE_HANDLERS[node.tag](node)
-
-class Nothing(object):
- pass
-
-
-class LLSDXMLFormatter(object):
- def __init__(self):
- self.type_map = {
- type(None) : self.UNDEF,
- bool : self.BOOLEAN,
- int : self.INTEGER,
- long : self.INTEGER,
- float : self.REAL,
- lluuid.UUID : self.UUID,
- binary : self.BINARY,
- str : self.STRING,
- unicode : self.STRING,
- uri : self.URI,
- datetime.datetime : self.DATE,
- datetime.date : self.DATE,
- list : self.ARRAY,
- tuple : self.ARRAY,
- types.GeneratorType : self.ARRAY,
- dict : self.MAP,
- LLSD : self.LLSD
- }
-
- def elt(self, name, contents=None):
- if(contents is None or contents is ''):
- return "<%s />" % (name,)
- else:
- if type(contents) is unicode:
- contents = contents.encode('utf-8')
- return "<%s>%s%s>" % (name, contents, name)
-
- def xml_esc(self, v):
- if type(v) is unicode:
- v = v.encode('utf-8')
- return v.replace('&', '&').replace('<', '<').replace('>', '>')
-
- def LLSD(self, v):
- return self.generate(v.thing)
- def UNDEF(self, v):
- return self.elt('undef')
- def BOOLEAN(self, v):
- if v:
- return self.elt('boolean', 'true')
- else:
- return self.elt('boolean', 'false')
- def INTEGER(self, v):
- return self.elt('integer', v)
- def REAL(self, v):
- return self.elt('real', v)
- def UUID(self, v):
- if(v.isNull()):
- return self.elt('uuid')
- else:
- return self.elt('uuid', v)
- def BINARY(self, v):
- return self.elt('binary', base64.encodestring(v))
- def STRING(self, v):
- return self.elt('string', self.xml_esc(v))
- def URI(self, v):
- return self.elt('uri', self.xml_esc(str(v)))
- def DATE(self, v):
- return self.elt('date', format_datestr(v))
- def ARRAY(self, v):
- return self.elt('array', ''.join([self.generate(item) for item in v]))
- def MAP(self, v):
- return self.elt(
- 'map',
- ''.join(["%s%s" % (self.elt('key', self.xml_esc(str(key))), self.generate(value))
- for key, value in v.items()]))
-
- typeof = type
- def generate(self, something):
- t = self.typeof(something)
- if self.type_map.has_key(t):
- return self.type_map[t](something)
- else:
- raise LLSDSerializationError("Cannot serialize unknown type: %s (%s)" % (
- t, something))
-
- def _format(self, something):
- return '' + self.elt("llsd", self.generate(something))
-
- def format(self, something):
- if cllsd:
- return cllsd.llsd_to_xml(something)
- return self._format(something)
-
-_g_xml_formatter = None
-def format_xml(something):
- global _g_xml_formatter
- if _g_xml_formatter is None:
- _g_xml_formatter = LLSDXMLFormatter()
- return _g_xml_formatter.format(something)
-
-class LLSDXMLPrettyFormatter(LLSDXMLFormatter):
- def __init__(self, indent_atom = None):
- # Call the super class constructor so that we have the type map
- super(LLSDXMLPrettyFormatter, self).__init__()
-
- # Override the type map to use our specialized formatters to
- # emit the pretty output.
- self.type_map[list] = self.PRETTY_ARRAY
- self.type_map[tuple] = self.PRETTY_ARRAY
- self.type_map[types.GeneratorType] = self.PRETTY_ARRAY,
- self.type_map[dict] = self.PRETTY_MAP
-
- # Private data used for indentation.
- self._indent_level = 1
- if indent_atom is None:
- self._indent_atom = ' '
- else:
- self._indent_atom = indent_atom
-
- def _indent(self):
- "Return an indentation based on the atom and indentation level."
- return self._indent_atom * self._indent_level
-
- def PRETTY_ARRAY(self, v):
- rv = []
- rv.append('\n')
- self._indent_level = self._indent_level + 1
- rv.extend(["%s%s\n" %
- (self._indent(),
- self.generate(item))
- for item in v])
- self._indent_level = self._indent_level - 1
- rv.append(self._indent())
- rv.append('')
- return ''.join(rv)
-
- def PRETTY_MAP(self, v):
- rv = []
- rv.append('')
- return ''.join(rv)
-
- def format(self, something):
- data = []
- data.append('\n')
- data.append(self.generate(something))
- data.append('\n')
- return '\n'.join(data)
-
-def format_pretty_xml(something):
- """@brief Serialize a python object as 'pretty' llsd xml.
-
- The output conforms to the LLSD DTD, unlike the output from the
- standard python xml.dom DOM::toprettyxml() method which does not
- preserve significant whitespace.
- This function is not necessarily suited for serializing very large
- objects. It is not optimized by the cllsd module, and sorts on
- dict (llsd map) keys alphabetically to ease human reading.
- """
- return LLSDXMLPrettyFormatter().format(something)
-
-class LLSDNotationFormatter(object):
- def __init__(self):
- self.type_map = {
- type(None) : self.UNDEF,
- bool : self.BOOLEAN,
- int : self.INTEGER,
- long : self.INTEGER,
- float : self.REAL,
- lluuid.UUID : self.UUID,
- binary : self.BINARY,
- str : self.STRING,
- unicode : self.STRING,
- uri : self.URI,
- datetime.datetime : self.DATE,
- datetime.date : self.DATE,
- list : self.ARRAY,
- tuple : self.ARRAY,
- types.GeneratorType : self.ARRAY,
- dict : self.MAP,
- LLSD : self.LLSD
- }
-
- def LLSD(self, v):
- return self.generate(v.thing)
- def UNDEF(self, v):
- return '!'
- def BOOLEAN(self, v):
- if v:
- return 'true'
- else:
- return 'false'
- def INTEGER(self, v):
- return "i%s" % v
- def REAL(self, v):
- return "r%s" % v
- def UUID(self, v):
- return "u%s" % v
- def BINARY(self, v):
- return 'b64"' + base64.encodestring(v) + '"'
- def STRING(self, v):
- if isinstance(v, unicode):
- v = v.encode('utf-8')
- return "'%s'" % v.replace("\\", "\\\\").replace("'", "\\'")
- def URI(self, v):
- return 'l"%s"' % str(v).replace("\\", "\\\\").replace('"', '\\"')
- def DATE(self, v):
- return 'd"%s"' % format_datestr(v)
- def ARRAY(self, v):
- return "[%s]" % ','.join([self.generate(item) for item in v])
- def MAP(self, v):
- def fix(key):
- if isinstance(key, unicode):
- return key.encode('utf-8')
- return key
- return "{%s}" % ','.join(["'%s':%s" % (fix(key).replace("\\", "\\\\").replace("'", "\\'"), self.generate(value))
- for key, value in v.items()])
-
- def generate(self, something):
- t = type(something)
- handler = self.type_map.get(t)
- if handler:
- return handler(something)
- else:
- try:
- return self.ARRAY(iter(something))
- except TypeError:
- raise LLSDSerializationError(
- "Cannot serialize unknown type: %s (%s)" % (t, something))
-
- def format(self, something):
- return self.generate(something)
-
-def format_notation(something):
- return LLSDNotationFormatter().format(something)
-
-def _hex_as_nybble(hex):
- if (hex >= '0') and (hex <= '9'):
- return ord(hex) - ord('0')
- elif (hex >= 'a') and (hex <='f'):
- return 10 + ord(hex) - ord('a')
- elif (hex >= 'A') and (hex <='F'):
- return 10 + ord(hex) - ord('A');
-
-class LLSDBinaryParser(object):
- def __init__(self):
- pass
-
- def parse(self, buffer, ignore_binary = False):
- """
- This is the basic public interface for parsing.
-
- @param buffer the binary data to parse in an indexable sequence.
- @param ignore_binary parser throws away data in llsd binary nodes.
- @return returns a python object.
- """
- self._buffer = buffer
- self._index = 0
- self._keep_binary = not ignore_binary
- return self._parse()
-
- def _parse(self):
- cc = self._buffer[self._index]
- self._index += 1
- if cc == '{':
- return self._parse_map()
- elif cc == '[':
- return self._parse_array()
- elif cc == '!':
- return None
- elif cc == '0':
- return False
- elif cc == '1':
- return True
- elif cc == 'i':
- # 'i' = integer
- idx = self._index
- self._index += 4
- return struct.unpack("!i", self._buffer[idx:idx+4])[0]
- elif cc == ('r'):
- # 'r' = real number
- idx = self._index
- self._index += 8
- return struct.unpack("!d", self._buffer[idx:idx+8])[0]
- elif cc == 'u':
- # 'u' = uuid
- idx = self._index
- self._index += 16
- return lluuid.uuid_bits_to_uuid(self._buffer[idx:idx+16])
- elif cc == 's':
- # 's' = string
- return self._parse_string()
- elif cc in ("'", '"'):
- # delimited/escaped string
- return self._parse_string_delim(cc)
- elif cc == 'l':
- # 'l' = uri
- return uri(self._parse_string())
- elif cc == ('d'):
- # 'd' = date in seconds since epoch
- idx = self._index
- self._index += 8
- seconds = struct.unpack("!d", self._buffer[idx:idx+8])[0]
- return datetime.datetime.fromtimestamp(seconds)
- elif cc == 'b':
- binary = self._parse_string()
- if self._keep_binary:
- return binary
- # *NOTE: maybe have a binary placeholder which has the
- # length.
- return None
- else:
- raise LLSDParseError("invalid binary token at byte %d: %d" % (
- self._index - 1, ord(cc)))
-
- def _parse_map(self):
- rv = {}
- size = struct.unpack("!i", self._buffer[self._index:self._index+4])[0]
- self._index += 4
- count = 0
- cc = self._buffer[self._index]
- self._index += 1
- key = ''
- while (cc != '}') and (count < size):
- if cc == 'k':
- key = self._parse_string()
- elif cc in ("'", '"'):
- key = self._parse_string_delim(cc)
- else:
- raise LLSDParseError("invalid map key at byte %d." % (
- self._index - 1,))
- value = self._parse()
- rv[key] = value
- count += 1
- cc = self._buffer[self._index]
- self._index += 1
- if cc != '}':
- raise LLSDParseError("invalid map close token at byte %d." % (
- self._index,))
- return rv
-
- def _parse_array(self):
- rv = []
- size = struct.unpack("!i", self._buffer[self._index:self._index+4])[0]
- self._index += 4
- count = 0
- cc = self._buffer[self._index]
- while (cc != ']') and (count < size):
- rv.append(self._parse())
- count += 1
- cc = self._buffer[self._index]
- if cc != ']':
- raise LLSDParseError("invalid array close token at byte %d." % (
- self._index,))
- self._index += 1
- return rv
-
- def _parse_string(self):
- size = struct.unpack("!i", self._buffer[self._index:self._index+4])[0]
- self._index += 4
- rv = self._buffer[self._index:self._index+size]
- self._index += size
- return rv
-
- def _parse_string_delim(self, delim):
- list = []
- found_escape = False
- found_hex = False
- found_digit = False
- byte = 0
- while True:
- cc = self._buffer[self._index]
- self._index += 1
- if found_escape:
- if found_hex:
- if found_digit:
- found_escape = False
- found_hex = False
- found_digit = False
- byte <<= 4
- byte |= _hex_as_nybble(cc)
- list.append(chr(byte))
- byte = 0
- else:
- found_digit = True
- byte = _hex_as_nybble(cc)
- elif cc == 'x':
- found_hex = True
- else:
- if cc == 'a':
- list.append('\a')
- elif cc == 'b':
- list.append('\b')
- elif cc == 'f':
- list.append('\f')
- elif cc == 'n':
- list.append('\n')
- elif cc == 'r':
- list.append('\r')
- elif cc == 't':
- list.append('\t')
- elif cc == 'v':
- list.append('\v')
- else:
- list.append(cc)
- found_escape = False
- elif cc == '\\':
- found_escape = True
- elif cc == delim:
- break
- else:
- list.append(cc)
- return ''.join(list)
-
-class LLSDNotationParser(object):
- """ Parse LLSD notation:
- map: { string:object, string:object }
- array: [ object, object, object ]
- undef: !
- boolean: true | false | 1 | 0 | T | F | t | f | TRUE | FALSE
- integer: i####
- real: r####
- uuid: u####
- string: "g\'day" | 'have a "nice" day' | s(size)"raw data"
- uri: l"escaped"
- date: d"YYYY-MM-DDTHH:MM:SS.FFZ"
- binary: b##"ff3120ab1" | b(size)"raw data"
- """
- def __init__(self):
- pass
-
- def parse(self, buffer, ignore_binary = False):
- """
- This is the basic public interface for parsing.
-
- @param buffer the notation string to parse.
- @param ignore_binary parser throws away data in llsd binary nodes.
- @return returns a python object.
- """
- if buffer == "":
- return False
-
- self._buffer = buffer
- self._index = 0
- return self._parse()
-
- def _parse(self):
- cc = self._buffer[self._index]
- self._index += 1
- if cc == '{':
- return self._parse_map()
- elif cc == '[':
- return self._parse_array()
- elif cc == '!':
- return None
- elif cc == '0':
- return False
- elif cc == '1':
- return True
- elif cc in ('F', 'f'):
- self._skip_alpha()
- return False
- elif cc in ('T', 't'):
- self._skip_alpha()
- return True
- elif cc == 'i':
- # 'i' = integer
- return self._parse_integer()
- elif cc == ('r'):
- # 'r' = real number
- return self._parse_real()
- elif cc == 'u':
- # 'u' = uuid
- return self._parse_uuid()
- elif cc in ("'", '"', 's'):
- return self._parse_string(cc)
- elif cc == 'l':
- # 'l' = uri
- delim = self._buffer[self._index]
- self._index += 1
- val = uri(self._parse_string(delim))
- if len(val) == 0:
- return None
- return val
- elif cc == ('d'):
- # 'd' = date in seconds since epoch
- return self._parse_date()
- elif cc == 'b':
- return self._parse_binary()
- else:
- raise LLSDParseError("invalid token at index %d: %d" % (
- self._index - 1, ord(cc)))
-
- def _parse_binary(self):
- i = self._index
- if self._buffer[i:i+2] == '64':
- q = self._buffer[i+2]
- e = self._buffer.find(q, i+3)
- try:
- return base64.decodestring(self._buffer[i+3:e])
- finally:
- self._index = e + 1
- else:
- raise LLSDParseError('random horrible binary format not supported')
-
- def _parse_map(self):
- """ map: { string:object, string:object } """
- rv = {}
- cc = self._buffer[self._index]
- self._index += 1
- key = ''
- found_key = False
- while (cc != '}'):
- if not found_key:
- if cc in ("'", '"', 's'):
- key = self._parse_string(cc)
- found_key = True
- elif cc.isspace() or cc == ',':
- cc = self._buffer[self._index]
- self._index += 1
- else:
- raise LLSDParseError("invalid map key at byte %d." % (
- self._index - 1,))
- elif cc.isspace() or cc == ':':
- cc = self._buffer[self._index]
- self._index += 1
- continue
- else:
- self._index += 1
- value = self._parse()
- rv[key] = value
- found_key = False
- cc = self._buffer[self._index]
- self._index += 1
-
- return rv
-
- def _parse_array(self):
- """ array: [ object, object, object ] """
- rv = []
- cc = self._buffer[self._index]
- while (cc != ']'):
- if cc.isspace() or cc == ',':
- self._index += 1
- cc = self._buffer[self._index]
- continue
- rv.append(self._parse())
- cc = self._buffer[self._index]
-
- if cc != ']':
- raise LLSDParseError("invalid array close token at index %d." % (
- self._index,))
- self._index += 1
- return rv
-
- def _parse_uuid(self):
- match = re.match(lluuid.UUID.uuid_regex, self._buffer[self._index:])
- if not match:
- raise LLSDParseError("invalid uuid token at index %d." % self._index)
-
- (start, end) = match.span()
- start += self._index
- end += self._index
- self._index = end
- return lluuid.UUID(self._buffer[start:end])
-
- def _skip_alpha(self):
- match = re.match(alpha_regex, self._buffer[self._index:])
- if match:
- self._index += match.end()
-
- def _parse_date(self):
- delim = self._buffer[self._index]
- self._index += 1
- datestr = self._parse_string(delim)
- return parse_datestr(datestr)
-
- def _parse_real(self):
- match = re.match(real_regex, self._buffer[self._index:])
- if not match:
- raise LLSDParseError("invalid real token at index %d." % self._index)
-
- (start, end) = match.span()
- start += self._index
- end += self._index
- self._index = end
- return float( self._buffer[start:end] )
-
- def _parse_integer(self):
- match = re.match(int_regex, self._buffer[self._index:])
- if not match:
- raise LLSDParseError("invalid integer token at index %d." % self._index)
-
- (start, end) = match.span()
- start += self._index
- end += self._index
- self._index = end
- return int( self._buffer[start:end] )
-
- def _parse_string(self, delim):
- """ string: "g\'day" | 'have a "nice" day' | s(size)"raw data" """
- rv = ""
-
- if delim in ("'", '"'):
- rv = self._parse_string_delim(delim)
- elif delim == 's':
- rv = self._parse_string_raw()
- else:
- raise LLSDParseError("invalid string token at index %d." % self._index)
-
- return rv
-
-
- def _parse_string_delim(self, delim):
- """ string: "g'day 'un" | 'have a "nice" day' """
- list = []
- found_escape = False
- found_hex = False
- found_digit = False
- byte = 0
- while True:
- cc = self._buffer[self._index]
- self._index += 1
- if found_escape:
- if found_hex:
- if found_digit:
- found_escape = False
- found_hex = False
- found_digit = False
- byte <<= 4
- byte |= _hex_as_nybble(cc)
- list.append(chr(byte))
- byte = 0
- else:
- found_digit = True
- byte = _hex_as_nybble(cc)
- elif cc == 'x':
- found_hex = True
- else:
- if cc == 'a':
- list.append('\a')
- elif cc == 'b':
- list.append('\b')
- elif cc == 'f':
- list.append('\f')
- elif cc == 'n':
- list.append('\n')
- elif cc == 'r':
- list.append('\r')
- elif cc == 't':
- list.append('\t')
- elif cc == 'v':
- list.append('\v')
- else:
- list.append(cc)
- found_escape = False
- elif cc == '\\':
- found_escape = True
- elif cc == delim:
- break
- else:
- list.append(cc)
- return ''.join(list)
-
- def _parse_string_raw(self):
- """ string: s(size)"raw data" """
- # Read the (size) portion.
- cc = self._buffer[self._index]
- self._index += 1
- if cc != '(':
- raise LLSDParseError("invalid string token at index %d." % self._index)
-
- rparen = self._buffer.find(')', self._index)
- if rparen == -1:
- raise LLSDParseError("invalid string token at index %d." % self._index)
-
- size = int(self._buffer[self._index:rparen])
-
- self._index = rparen + 1
- delim = self._buffer[self._index]
- self._index += 1
- if delim not in ("'", '"'):
- raise LLSDParseError("invalid string token at index %d." % self._index)
-
- rv = self._buffer[self._index:(self._index + size)]
- self._index += size
- cc = self._buffer[self._index]
- self._index += 1
- if cc != delim:
- raise LLSDParseError("invalid string token at index %d." % self._index)
-
- return rv
-
-def format_binary(something):
- return '\n' + _format_binary_recurse(something)
-
-def _format_binary_recurse(something):
- def _format_list(something):
- array_builder = []
- array_builder.append('[' + struct.pack('!i', len(something)))
- for item in something:
- array_builder.append(_format_binary_recurse(item))
- array_builder.append(']')
- return ''.join(array_builder)
-
- if something is None:
- return '!'
- elif isinstance(something, LLSD):
- return _format_binary_recurse(something.thing)
- elif isinstance(something, bool):
- if something:
- return '1'
- else:
- return '0'
- elif isinstance(something, (int, long)):
- return 'i' + struct.pack('!i', something)
- elif isinstance(something, float):
- return 'r' + struct.pack('!d', something)
- elif isinstance(something, lluuid.UUID):
- return 'u' + something._bits
- elif isinstance(something, binary):
- return 'b' + struct.pack('!i', len(something)) + something
- elif isinstance(something, str):
- return 's' + struct.pack('!i', len(something)) + something
- elif isinstance(something, unicode):
- something = something.encode('utf-8')
- return 's' + struct.pack('!i', len(something)) + something
- elif isinstance(something, uri):
- return 'l' + struct.pack('!i', len(something)) + something
- elif isinstance(something, datetime.datetime):
- seconds_since_epoch = time.mktime(something.timetuple())
- return 'd' + struct.pack('!d', seconds_since_epoch)
- elif isinstance(something, (list, tuple)):
- return _format_list(something)
- elif isinstance(something, dict):
- map_builder = []
- map_builder.append('{' + struct.pack('!i', len(something)))
- for key, value in something.items():
- if isinstance(key, unicode):
- key = key.encode('utf-8')
- map_builder.append('k' + struct.pack('!i', len(key)) + key)
- map_builder.append(_format_binary_recurse(value))
- map_builder.append('}')
- return ''.join(map_builder)
- else:
- try:
- return _format_list(list(something))
- except TypeError:
- raise LLSDSerializationError(
- "Cannot serialize unknown type: %s (%s)" %
- (type(something), something))
-
-
-def parse_binary(binary):
- if binary.startswith(''):
- just_binary = binary.split('\n', 1)[1]
- else:
- just_binary = binary
- return LLSDBinaryParser().parse(just_binary)
-
-def parse_xml(something):
- try:
- return to_python(fromstring(something)[0])
- except ElementTreeError, err:
- raise LLSDParseError(*err.args)
-
-def parse_notation(something):
- return LLSDNotationParser().parse(something)
-
-def parse(something):
- try:
- something = string.lstrip(something) #remove any pre-trailing whitespace
- if something.startswith(''):
- return parse_binary(something)
- # This should be better.
- elif something.startswith('<'):
- return parse_xml(something)
- else:
- return parse_notation(something)
- except KeyError, e:
- raise Exception('LLSD could not be parsed: %s' % (e,))
-
-class LLSD(object):
- def __init__(self, thing=None):
- self.thing = thing
-
- def __str__(self):
- return self.toXML(self.thing)
-
- parse = staticmethod(parse)
- toXML = staticmethod(format_xml)
- toPrettyXML = staticmethod(format_pretty_xml)
- toBinary = staticmethod(format_binary)
- toNotation = staticmethod(format_notation)
-
-
-undef = LLSD(None)
-
-XML_MIME_TYPE = 'application/llsd+xml'
-BINARY_MIME_TYPE = 'application/llsd+binary'
-
-# register converters for llsd in mulib, if it is available
-try:
- from mulib import stacked, mu
- stacked.NoProducer() # just to exercise stacked
- mu.safe_load(None) # just to exercise mu
-except:
- # mulib not available, don't print an error message since this is normal
- pass
-else:
- mu.add_parser(parse, XML_MIME_TYPE)
- mu.add_parser(parse, 'application/llsd+binary')
-
- def llsd_convert_xml(llsd_stuff, request):
- request.write(format_xml(llsd_stuff))
-
- def llsd_convert_binary(llsd_stuff, request):
- request.write(format_binary(llsd_stuff))
-
- for typ in [LLSD, dict, list, tuple, str, int, long, float, bool, unicode, type(None)]:
- stacked.add_producer(typ, llsd_convert_xml, XML_MIME_TYPE)
- stacked.add_producer(typ, llsd_convert_xml, 'application/xml')
- stacked.add_producer(typ, llsd_convert_xml, 'text/xml')
-
- stacked.add_producer(typ, llsd_convert_binary, 'application/llsd+binary')
-
- stacked.add_producer(LLSD, llsd_convert_xml, '*/*')
-
- # in case someone is using the legacy mu.xml wrapper, we need to
- # tell mu to produce application/xml or application/llsd+xml
- # (based on the accept header) from raw xml. Phoenix 2008-07-21
- stacked.add_producer(mu.xml, mu.produce_raw, XML_MIME_TYPE)
- stacked.add_producer(mu.xml, mu.produce_raw, 'application/xml')
-
-
-
-# mulib wsgi stuff
-# try:
-# from mulib import mu, adapters
-#
-# # try some known attributes from mulib to be ultra-sure we've imported it
-# mu.get_current
-# adapters.handlers
-# except:
-# # mulib not available, don't print an error message since this is normal
-# pass
-# else:
-# def llsd_xml_handler(content_type):
-# def handle_llsd_xml(env, start_response):
-# llsd_stuff, _ = mu.get_current(env)
-# result = format_xml(llsd_stuff)
-# start_response("200 OK", [('Content-Type', content_type)])
-# env['mu.negotiated_type'] = content_type
-# yield result
-# return handle_llsd_xml
-#
-# def llsd_binary_handler(content_type):
-# def handle_llsd_binary(env, start_response):
-# llsd_stuff, _ = mu.get_current(env)
-# result = format_binary(llsd_stuff)
-# start_response("200 OK", [('Content-Type', content_type)])
-# env['mu.negotiated_type'] = content_type
-# yield result
-# return handle_llsd_binary
-#
-# adapters.DEFAULT_PARSERS[XML_MIME_TYPE] = parse
-
-# for typ in [LLSD, dict, list, tuple, str, int, float, bool, unicode, type(None)]:
-# for content_type in (XML_MIME_TYPE, 'application/xml'):
-# adapters.handlers.set_handler(typ, llsd_xml_handler(content_type), content_type)
-#
-# adapters.handlers.set_handler(typ, llsd_binary_handler(BINARY_MIME_TYPE), BINARY_MIME_TYPE)
-#
-# adapters.handlers.set_handler(LLSD, llsd_xml_handler(XML_MIME_TYPE), '*/*')
diff --git a/indra/lib/python/indra/base/lluuid.py b/indra/lib/python/indra/base/lluuid.py
deleted file mode 100644
index 7413ffe10d..0000000000
--- a/indra/lib/python/indra/base/lluuid.py
+++ /dev/null
@@ -1,319 +0,0 @@
-"""\
-@file lluuid.py
-@brief UUID parser/generator.
-
-$LicenseInfo:firstyear=2004&license=mit$
-
-Copyright (c) 2004-2009, Linden Research, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-$/LicenseInfo$
-"""
-
-import random, socket, string, time, re
-import uuid
-try:
- # Python 2.6
- from hashlib import md5
-except ImportError:
- # Python 2.5 and earlier
- from md5 import new as md5
-
-def _int2binstr(i,l):
- s=''
- for a in range(l):
- s=chr(i&0xFF)+s
- i>>=8
- return s
-
-def _binstr2int(s):
- i = long(0)
- for c in s:
- i = (i<<8) + ord(c)
- return i
-
-class UUID(object):
- """
- A class which represents a 16 byte integer. Stored as a 16 byte 8
- bit character string.
-
- The string version is to be of the form:
- AAAAAAAA-AAAA-BBBB-BBBB-BBBBBBCCCCCC (a 128-bit number in hex)
- where A=network address, B=timestamp, C=random.
- """
-
- NULL_STR = "00000000-0000-0000-0000-000000000000"
-
- # the UUIDREGEX_STRING is helpful for parsing UUID's in text
- hex_wildcard = r"[0-9a-fA-F]"
- word = hex_wildcard + r"{4,4}-"
- long_word = hex_wildcard + r"{8,8}-"
- very_long_word = hex_wildcard + r"{12,12}"
- UUID_REGEX_STRING = long_word + word + word + word + very_long_word
- uuid_regex = re.compile(UUID_REGEX_STRING)
-
- rand = random.Random()
- ip = ''
- try:
- ip = socket.gethostbyname(socket.gethostname())
- except(socket.gaierror, socket.error):
- # no ip address, so just default to somewhere in 10.x.x.x
- ip = '10'
- for i in range(3):
- ip += '.' + str(rand.randrange(1,254))
- hexip = ''.join(["%04x" % long(i) for i in ip.split('.')])
- lastid = ''
-
- def __init__(self, possible_uuid=None):
- """
- Initialize to first valid UUID in argument (if a string),
- or to null UUID if none found or argument is not supplied.
-
- If the argument is a UUID, the constructed object will be a copy of it.
- """
- self._bits = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
- if possible_uuid is None:
- return
-
- if isinstance(possible_uuid, type(self)):
- self.set(possible_uuid)
- return
-
- uuid_match = UUID.uuid_regex.search(possible_uuid)
- if uuid_match:
- uuid_string = uuid_match.group()
- s = string.replace(uuid_string, '-', '')
- self._bits = _int2binstr(string.atol(s[:8],16),4) + \
- _int2binstr(string.atol(s[8:16],16),4) + \
- _int2binstr(string.atol(s[16:24],16),4) + \
- _int2binstr(string.atol(s[24:],16),4)
-
- def __len__(self):
- """
- Used by the len() builtin.
- """
- return 36
-
- def __nonzero__(self):
- return self._bits != "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
-
- def __str__(self):
- uuid_string = self.toString()
- return uuid_string
-
- __repr__ = __str__
-
- def __getitem__(self, index):
- return str(self)[index]
-
- def __eq__(self, other):
- if isinstance(other, (str, unicode)):
- return other == str(self)
- return self._bits == getattr(other, '_bits', '')
-
- def __ne__(self, other):
- return not self.__eq__(other)
-
- def __le__(self, other):
- return self._bits <= other._bits
-
- def __ge__(self, other):
- return self._bits >= other._bits
-
- def __lt__(self, other):
- return self._bits < other._bits
-
- def __gt__(self, other):
- return self._bits > other._bits
-
- def __hash__(self):
- return hash(self._bits)
-
- def set(self, uuid):
- self._bits = uuid._bits
-
- def setFromString(self, uuid_string):
- """
- Given a string version of a uuid, set self bits
- appropriately. Returns self.
- """
- s = string.replace(uuid_string, '-', '')
- self._bits = _int2binstr(string.atol(s[:8],16),4) + \
- _int2binstr(string.atol(s[8:16],16),4) + \
- _int2binstr(string.atol(s[16:24],16),4) + \
- _int2binstr(string.atol(s[24:],16),4)
- return self
-
- def setFromMemoryDump(self, gdb_string):
- """
- We expect to get gdb_string as four hex units. eg:
- 0x147d54db 0xc34b3f1b 0x714f989b 0x0a892fd2
- Which will be translated to:
- db547d14-1b3f4bc3-9b984f71-d22f890a
- Returns self.
- """
- s = string.replace(gdb_string, '0x', '')
- s = string.replace(s, ' ', '')
- t = ''
- for i in range(8,40,8):
- for j in range(0,8,2):
- t = t + s[i-j-2:i-j]
- self.setFromString(t)
-
- def toString(self):
- """
- Return as a string matching the LL standard
- AAAAAAAA-AAAA-BBBB-BBBB-BBBBBBCCCCCC (a 128-bit number in hex)
- where A=network address, B=timestamp, C=random.
- """
- return uuid_bits_to_string(self._bits)
-
- def getAsString(self):
- """
- Return a different string representation of the form
- AAAAAAAA-AAAABBBB-BBBBBBBB-BBCCCCCC (a 128-bit number in hex)
- where A=network address, B=timestamp, C=random.
- """
- i1 = _binstr2int(self._bits[0:4])
- i2 = _binstr2int(self._bits[4:8])
- i3 = _binstr2int(self._bits[8:12])
- i4 = _binstr2int(self._bits[12:16])
- return '%08lx-%08lx-%08lx-%08lx' % (i1,i2,i3,i4)
-
- def generate(self):
- """
- Generate a new uuid. This algorithm is slightly different
- from c++ implementation for portability reasons.
- Returns self.
- """
- m = md5()
- m.update(uuid.uuid1().bytes)
- self._bits = m.digest()
- return self
-
- def isNull(self):
- """
- Returns 1 if the uuid is null - ie, equal to default uuid.
- """
- return (self._bits == "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0")
-
- def xor(self, rhs):
- """
- xors self with rhs.
- """
- v1 = _binstr2int(self._bits[0:4]) ^ _binstr2int(rhs._bits[0:4])
- v2 = _binstr2int(self._bits[4:8]) ^ _binstr2int(rhs._bits[4:8])
- v3 = _binstr2int(self._bits[8:12]) ^ _binstr2int(rhs._bits[8:12])
- v4 = _binstr2int(self._bits[12:16]) ^ _binstr2int(rhs._bits[12:16])
- self._bits = _int2binstr(v1,4) + \
- _int2binstr(v2,4) + \
- _int2binstr(v3,4) + \
- _int2binstr(v4,4)
-
-
-# module-level null constant
-NULL = UUID()
-
-def printTranslatedMemory(four_hex_uints):
- """
- We expect to get the string as four hex units. eg:
- 0x147d54db 0xc34b3f1b 0x714f989b 0x0a892fd2
- Which will be translated to:
- db547d14-1b3f4bc3-9b984f71-d22f890a
- """
- uuid = UUID()
- uuid.setFromMemoryDump(four_hex_uints)
- print uuid.toString()
-
-def isUUID(id_str):
- """
- This function returns:
- - 1 if the string passed is a UUID
- - 0 is the string passed is not a UUID
- - None if it neither of the if's below is satisfied
- """
- if not id_str or len(id_str) < 5 or len(id_str) > 36:
- return 0
-
- if isinstance(id_str, UUID) or UUID.uuid_regex.match(id_str):
- return 1
-
- return None
-
-def isPossiblyID(id_str):
- """
- This function returns 1 if the string passed has some uuid-like
- characteristics. Otherwise returns 0.
- """
-
- is_uuid = isUUID(id_str)
- if is_uuid is not None:
- return is_uuid
-
- # build a string which matches every character.
- hex_wildcard = r"[0-9a-fA-F]"
- chars = len(id_str)
- next = min(chars, 8)
- matcher = hex_wildcard+"{"+str(next)+","+str(next)+"}"
- chars = chars - next
- if chars > 0:
- matcher = matcher + "-"
- chars = chars - 1
- for block in range(3):
- next = max(min(chars, 4), 0)
- if next:
- matcher = matcher + hex_wildcard+"{"+str(next)+","+str(next)+"}"
- chars = chars - next
- if chars > 0:
- matcher = matcher + "-"
- chars = chars - 1
- if chars > 0:
- next = min(chars, 12)
- matcher = matcher + hex_wildcard+"{"+str(next)+","+str(next)+"}"
- #print matcher
- uuid_matcher = re.compile(matcher)
- if uuid_matcher.match(id_str):
- return 1
- return 0
-
-def uuid_bits_to_string(bits):
- i1 = _binstr2int(bits[0:4])
- i2 = _binstr2int(bits[4:6])
- i3 = _binstr2int(bits[6:8])
- i4 = _binstr2int(bits[8:10])
- i5 = _binstr2int(bits[10:12])
- i6 = _binstr2int(bits[12:16])
- return '%08lx-%04lx-%04lx-%04lx-%04lx%08lx' % (i1,i2,i3,i4,i5,i6)
-
-def uuid_bits_to_uuid(bits):
- return UUID(uuid_bits_to_string(bits))
-
-
-try:
- from mulib import stacked
- stacked.NoProducer() # just to exercise stacked
-except:
- #print "Couldn't import mulib.stacked, not registering UUID converter"
- pass
-else:
- def convertUUID(uuid, req):
- req.write(str(uuid))
-
- stacked.add_producer(UUID, convertUUID, "*/*")
- stacked.add_producer(UUID, convertUUID, "text/html")
diff --git a/indra/lib/python/indra/base/metrics.py b/indra/lib/python/indra/base/metrics.py
deleted file mode 100644
index ff8380265f..0000000000
--- a/indra/lib/python/indra/base/metrics.py
+++ /dev/null
@@ -1,121 +0,0 @@
-"""\
-@file metrics.py
-@author Phoenix
-@date 2007-11-27
-@brief simple interface for logging metrics
-
-$LicenseInfo:firstyear=2007&license=mit$
-
-Copyright (c) 2007-2009, Linden Research, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-$/LicenseInfo$
-"""
-
-import sys
-try:
- import syslog
-except ImportError:
- # Windows
- import sys
- class syslog(object):
- # wrap to a lame syslog for windows
- _logfp = sys.stderr
- def syslog(msg):
- _logfp.write(msg)
- if not msg.endswith('\n'):
- _logfp.write('\n')
- syslog = staticmethod(syslog)
-
-from indra.base.llsd import format_notation
-
-def record_metrics(table, stats):
- "Write a standard metrics log"
- _log("LLMETRICS", table, stats)
-
-def record_event(table, data):
- "Write a standard logmessage log"
- _log("LLLOGMESSAGE", table, data)
-
-def set_destination(dest):
- """Set the destination of metrics logs for this process.
-
- If you do not call this function prior to calling a logging
- method, that function will open sys.stdout as a destination.
- Attempts to set dest to None will throw a RuntimeError.
- @param dest a file-like object which will be the destination for logs."""
- if dest is None:
- raise RuntimeError("Attempt to unset metrics destination.")
- global _destination
- _destination = dest
-
-def destination():
- """Get the destination of the metrics logs for this process.
- Returns None if no destination is set"""
- global _destination
- return _destination
-
-class SysLogger(object):
- "A file-like object which writes to syslog."
- def __init__(self, ident='indra', logopt = None, facility = None):
- try:
- if logopt is None:
- logopt = syslog.LOG_CONS | syslog.LOG_PID
- if facility is None:
- facility = syslog.LOG_LOCAL0
- syslog.openlog(ident, logopt, facility)
- import atexit
- atexit.register(syslog.closelog)
- except AttributeError:
- # No syslog module on Windows
- pass
-
- def write(str):
- syslog.syslog(str)
- write = staticmethod(write)
-
- def flush():
- pass
- flush = staticmethod(flush)
-
-#
-# internal API
-#
-_sequence_id = 0
-_destination = None
-
-def _next_id():
- global _sequence_id
- next = _sequence_id
- _sequence_id += 1
- return next
-
-def _dest():
- global _destination
- if _destination is None:
- # this default behavior is documented in the metrics functions above.
- _destination = sys.stdout
- return _destination
-
-def _log(header, table, data):
- log_line = "%s (%d) %s %s" \
- % (header, _next_id(), table, format_notation(data))
- dest = _dest()
- dest.write(log_line)
- dest.flush()
diff --git a/indra/lib/python/indra/ipc/httputil.py b/indra/lib/python/indra/ipc/httputil.py
deleted file mode 100644
index c4ac0a379d..0000000000
--- a/indra/lib/python/indra/ipc/httputil.py
+++ /dev/null
@@ -1,9 +0,0 @@
-
-import warnings
-
-warnings.warn("indra.ipc.httputil has been deprecated; use eventlet.httpc instead", DeprecationWarning, 2)
-
-from eventlet.httpc import *
-
-
-makeConnection = make_connection
diff --git a/indra/lib/python/indra/ipc/llsdhttp.py b/indra/lib/python/indra/ipc/llsdhttp.py
deleted file mode 100644
index cbe8ee1eca..0000000000
--- a/indra/lib/python/indra/ipc/llsdhttp.py
+++ /dev/null
@@ -1,100 +0,0 @@
-"""\
-@file llsdhttp.py
-@brief Functions to ease moving llsd over http
-
-$LicenseInfo:firstyear=2006&license=mit$
-
-Copyright (c) 2006-2009, Linden Research, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-$/LicenseInfo$
-"""
-
-import os.path
-import os
-import urlparse
-
-from indra.base import llsd
-
-from eventlet import httpc
-
-suite = httpc.HttpSuite(llsd.format_xml, llsd.parse, 'application/llsd+xml')
-delete = suite.delete
-delete_ = suite.delete_
-get = suite.get
-get_ = suite.get_
-head = suite.head
-head_ = suite.head_
-post = suite.post
-post_ = suite.post_
-put = suite.put
-put_ = suite.put_
-request = suite.request
-request_ = suite.request_
-
-# import every httpc error exception into our namespace for convenience
-for x in httpc.status_to_error_map.itervalues():
- globals()[x.__name__] = x
-ConnectionError = httpc.ConnectionError
-Retriable = httpc.Retriable
-
-for x in (httpc.ConnectionError,):
- globals()[x.__name__] = x
-
-
-def postFile(url, filename):
- f = open(filename)
- body = f.read()
- f.close()
- llsd_body = llsd.parse(body)
- return post_(url, llsd_body)
-
-
-# deprecated in favor of get_
-def getStatus(url, use_proxy=False):
- status, _headers, _body = get_(url, use_proxy=use_proxy)
- return status
-
-# deprecated in favor of put_
-def putStatus(url, data):
- status, _headers, _body = put_(url, data)
- return status
-
-# deprecated in favor of delete_
-def deleteStatus(url):
- status, _headers, _body = delete_(url)
- return status
-
-# deprecated in favor of post_
-def postStatus(url, data):
- status, _headers, _body = post_(url, data)
- return status
-
-
-def postFileStatus(url, filename):
- status, _headers, body = postFile(url, filename)
- return status, body
-
-
-def getFromSimulator(path, use_proxy=False):
- return get('http://' + simulatorHostAndPort + path, use_proxy=use_proxy)
-
-
-def postToSimulator(path, data=None):
- return post('http://' + simulatorHostAndPort + path, data)
diff --git a/indra/lib/python/indra/ipc/mysql_pool.py b/indra/lib/python/indra/ipc/mysql_pool.py
deleted file mode 100644
index e5855a3091..0000000000
--- a/indra/lib/python/indra/ipc/mysql_pool.py
+++ /dev/null
@@ -1,81 +0,0 @@
-"""\
-@file mysql_pool.py
-@brief Thin wrapper around eventlet.db_pool that chooses MySQLdb and Tpool.
-
-$LicenseInfo:firstyear=2007&license=mit$
-
-Copyright (c) 2007-2009, Linden Research, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-$/LicenseInfo$
-"""
-
-import MySQLdb
-from eventlet import db_pool
-
-class DatabaseConnector(db_pool.DatabaseConnector):
- def __init__(self, credentials, *args, **kwargs):
- super(DatabaseConnector, self).__init__(MySQLdb, credentials,
- conn_pool=db_pool.ConnectionPool,
- *args, **kwargs)
-
- # get is extended relative to eventlet.db_pool to accept a port argument
- def get(self, host, dbname, port=3306):
- key = (host, dbname, port)
- if key not in self._databases:
- new_kwargs = self._kwargs.copy()
- new_kwargs['db'] = dbname
- new_kwargs['host'] = host
- new_kwargs['port'] = port
- new_kwargs.update(self.credentials_for(host))
- dbpool = ConnectionPool(*self._args, **new_kwargs)
- self._databases[key] = dbpool
-
- return self._databases[key]
-
-class ConnectionPool(db_pool.TpooledConnectionPool):
- """A pool which gives out saranwrapped MySQLdb connections from a pool
- """
-
- def __init__(self, *args, **kwargs):
- super(ConnectionPool, self).__init__(MySQLdb, *args, **kwargs)
-
- def get(self):
- conn = super(ConnectionPool, self).get()
- # annotate the connection object with the details on the
- # connection; this is used elsewhere to check that you haven't
- # suddenly changed databases in midstream while making a
- # series of queries on a connection.
- arg_names = ['host','user','passwd','db','port','unix_socket','conv','connect_timeout',
- 'compress', 'named_pipe', 'init_command', 'read_default_file', 'read_default_group',
- 'cursorclass', 'use_unicode', 'charset', 'sql_mode', 'client_flag', 'ssl',
- 'local_infile']
- # you could have constructed this connectionpool with a mix of
- # keyword and non-keyword arguments, but we want to annotate
- # the connection object with a dict so it's easy to check
- # against so here we are converting the list of non-keyword
- # arguments (in self._args) into a dict of keyword arguments,
- # and merging that with the actual keyword arguments
- # (self._kwargs). The arg_names variable lists the
- # constructor arguments for MySQLdb Connection objects.
- converted_kwargs = dict([ (arg_names[i], arg) for i, arg in enumerate(self._args) ])
- converted_kwargs.update(self._kwargs)
- conn.connection_parameters = converted_kwargs
- return conn
-
diff --git a/indra/lib/python/indra/ipc/russ.py b/indra/lib/python/indra/ipc/russ.py
deleted file mode 100644
index 35d8afb158..0000000000
--- a/indra/lib/python/indra/ipc/russ.py
+++ /dev/null
@@ -1,165 +0,0 @@
-"""\
-@file russ.py
-@brief Recursive URL Substitution Syntax helpers
-@author Phoenix
-
-Many details on how this should work is available on the wiki:
-https://wiki.secondlife.com/wiki/Recursive_URL_Substitution_Syntax
-
-Adding features to this should be reflected in that page in the
-implementations section.
-
-$LicenseInfo:firstyear=2007&license=mit$
-
-Copyright (c) 2007-2009, Linden Research, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-$/LicenseInfo$
-"""
-
-import urllib
-from indra.ipc import llsdhttp
-
-class UnbalancedBraces(Exception):
- pass
-
-class UnknownDirective(Exception):
- pass
-
-class BadDirective(Exception):
- pass
-
-def format_value_for_path(value):
- if type(value) in [list, tuple]:
- # *NOTE: treat lists as unquoted path components so that the quoting
- # doesn't get out-of-hand. This is a workaround for the fact that
- # russ always quotes, even if the data it's given is already quoted,
- # and it's not safe to simply unquote a path directly, so if we want
- # russ to substitute urls parts inside other url parts we always
- # have to do so via lists of unquoted path components.
- return '/'.join([urllib.quote(str(item)) for item in value])
- else:
- return urllib.quote(str(value))
-
-def format(format_str, context):
- """@brief Format format string according to rules for RUSS.
-@see https://osiris.lindenlab.com/mediawiki/index.php/Recursive_URL_Substitution_Syntax
-@param format_str The input string to format.
-@param context A map used for string substitutions.
-@return Returns the formatted string. If no match, the braces remain intact.
-"""
- while True:
- #print "format_str:", format_str
- all_matches = _find_sub_matches(format_str)
- if not all_matches:
- break
- substitutions = 0
- while True:
- matches = all_matches.pop()
- # we work from right to left to make sure we do not
- # invalidate positions earlier in format_str
- matches.reverse()
- for pos in matches:
- # Use index since _find_sub_matches should have raised
- # an exception, and failure to find now is an exception.
- end = format_str.index('}', pos)
- #print "directive:", format_str[pos+1:pos+5]
- if format_str[pos + 1] == '$':
- value = context[format_str[pos + 2:end]]
- if value is not None:
- value = format_value_for_path(value)
- elif format_str[pos + 1] == '%':
- value = _build_query_string(
- context.get(format_str[pos + 2:end]))
- elif format_str[pos+1:pos+5] == 'http' or format_str[pos+1:pos+5] == 'file':
- value = _fetch_url_directive(format_str[pos + 1:end])
- else:
- raise UnknownDirective, format_str[pos:end + 1]
- if value is not None:
- format_str = format_str[:pos]+str(value)+format_str[end+1:]
- substitutions += 1
-
- # If there were any substitutions at this depth, re-parse
- # since this may have revealed new things to substitute
- if substitutions:
- break
- if not all_matches:
- break
-
- # If there were no substitutions at all, and we have exhausted
- # the possible matches, bail.
- if not substitutions:
- break
- return format_str
-
-def _find_sub_matches(format_str):
- """@brief Find all of the substitution matches.
-@param format_str the RUSS conformant format string.
-@return Returns an array of depths of arrays of positional matches in input.
-"""
- depth = 0
- matches = []
- for pos in range(len(format_str)):
- if format_str[pos] == '{':
- depth += 1
- if not len(matches) == depth:
- matches.append([])
- matches[depth - 1].append(pos)
- continue
- if format_str[pos] == '}':
- depth -= 1
- continue
- if not depth == 0:
- raise UnbalancedBraces, format_str
- return matches
-
-def _build_query_string(query_dict):
- """\
- @breif given a dict, return a query string. utility wrapper for urllib.
- @param query_dict input query dict
- @returns Returns an urlencoded query string including leading '?'.
- """
- if query_dict:
- keys = query_dict.keys()
- keys.sort()
- def stringize(value):
- if type(value) in (str,unicode):
- return value
- else:
- return str(value)
- query_list = [urllib.quote(str(key)) + '=' + urllib.quote(stringize(query_dict[key])) for key in keys]
- return '?' + '&'.join(query_list)
- else:
- return ''
-
-def _fetch_url_directive(directive):
- "*FIX: This only supports GET"
- commands = directive.split('|')
- resource = llsdhttp.get(commands[0])
- if len(commands) == 3:
- resource = _walk_resource(resource, commands[2])
- return resource
-
-def _walk_resource(resource, path):
- path = path.split('/')
- for child in path:
- if not child:
- continue
- resource = resource[child]
- return resource
diff --git a/indra/lib/python/indra/ipc/servicebuilder.py b/indra/lib/python/indra/ipc/servicebuilder.py
deleted file mode 100644
index 0a0ce2b4e2..0000000000
--- a/indra/lib/python/indra/ipc/servicebuilder.py
+++ /dev/null
@@ -1,134 +0,0 @@
-"""\
-@file servicebuilder.py
-@author Phoenix
-@brief Class which will generate service urls.
-
-$LicenseInfo:firstyear=2007&license=mit$
-
-Copyright (c) 2007-2009, Linden Research, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-$/LicenseInfo$
-"""
-
-from indra.base import config
-from indra.ipc import llsdhttp
-from indra.ipc import russ
-
-# *NOTE: agent presence relies on this variable existing and being current, it is a huge hack
-services_config = {}
-try:
- services_config = llsdhttp.get(config.get('services-config'))
-except:
- pass
-
-_g_builder = None
-def _builder():
- global _g_builder
- if _g_builder is None:
- _g_builder = ServiceBuilder()
- return _g_builder
-
-def build(name, context={}, **kwargs):
- """ Convenience method for using a global, singleton, service builder. Pass arguments either via a dict or via python keyword arguments, or both!
-
- Example use:
- > context = {'channel':'Second Life Release', 'version':'1.18.2.0'}
- > servicebuilder.build('version-manager-version', context)
- 'http://int.util.vaak.lindenlab.com/channel/Second%20Life%20Release/1.18.2.0'
- > servicebuilder.build('version-manager-version', channel='Second Life Release', version='1.18.2.0')
- 'http://int.util.vaak.lindenlab.com/channel/Second%20Life%20Release/1.18.2.0'
- > servicebuilder.build('version-manager-version', context, version='1.18.1.2')
- 'http://int.util.vaak.lindenlab.com/channel/Second%20Life%20Release/1.18.1.2'
- """
- global _g_builder
- if _g_builder is None:
- _g_builder = ServiceBuilder()
- return _g_builder.buildServiceURL(name, context, **kwargs)
-
-def build_path(name, context={}, **kwargs):
- context = context.copy() # shouldn't modify the caller's dictionary
- context.update(kwargs)
- return _builder().buildPath(name, context)
-
-class ServiceBuilder(object):
- def __init__(self, services_definition = services_config):
- """\
- @brief
- @brief Create a ServiceBuilder.
- @param services_definition Complete services definition, services.xml.
- """
- # no need to keep a copy of the services section of the
- # complete services definition, but it doesn't hurt much.
- self.services = services_definition['services']
- self.builders = {}
- for service in self.services:
- service_builder = service.get('service-builder')
- if not service_builder:
- continue
- if isinstance(service_builder, dict):
- # We will be constructing several builders
- for name, builder in service_builder.iteritems():
- full_builder_name = service['name'] + '-' + name
- self.builders[full_builder_name] = builder
- else:
- self.builders[service['name']] = service_builder
-
- def buildPath(self, name, context):
- """\
- @brief given the environment on construction, return a service path.
- @param name The name of the service.
- @param context A dict of name value lookups for the service.
- @returns Returns the
- """
- return russ.format(self.builders[name], context)
-
- def buildServiceURL(self, name, context={}, **kwargs):
- """\
- @brief given the environment on construction, return a service URL.
- @param name The name of the service.
- @param context A dict of name value lookups for the service.
- @param kwargs Any keyword arguments are treated as members of the
- context, this allows you to be all 31337 by writing shit like:
- servicebuilder.build('name', param=value)
- @returns Returns the
- """
- context = context.copy() # shouldn't modify the caller's dictionary
- context.update(kwargs)
- base_url = config.get('services-base-url')
- svc_path = russ.format(self.builders[name], context)
- return base_url + svc_path
-
-
-def on_in(query_name, host_key, schema_key):
- """\
- @brief Constructs an on/in snippet (for running named queries)
- from a schema name and two keys referencing values stored in
- indra.xml.
-
- @param query_name Name of the query.
- @param host_key Logical name of destination host. Will be
- looked up in indra.xml.
- @param schema_key Logical name of destination schema. Will
- be looked up in indra.xml.
- """
- return "on/config:%s/in/config:%s/%s" % (host_key.strip('/'),
- schema_key.strip('/'),
- query_name.lstrip('/'))
-
diff --git a/indra/lib/python/indra/ipc/siesta.py b/indra/lib/python/indra/ipc/siesta.py
deleted file mode 100644
index d867e71537..0000000000
--- a/indra/lib/python/indra/ipc/siesta.py
+++ /dev/null
@@ -1,468 +0,0 @@
-"""\
-@file siesta.py
-@brief A tiny llsd based RESTful web services framework
-
-$LicenseInfo:firstyear=2008&license=mit$
-
-Copyright (c) 2008, Linden Research, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-$/LicenseInfo$
-"""
-
-from indra.base import config
-from indra.base import llsd
-from webob import exc
-import webob
-import re, socket
-
-try:
- from cStringIO import StringIO
-except ImportError:
- from StringIO import StringIO
-
-try:
- import cjson
- json_decode = cjson.decode
- json_encode = cjson.encode
- JsonDecodeError = cjson.DecodeError
- JsonEncodeError = cjson.EncodeError
-except ImportError:
- import simplejson
- json_decode = simplejson.loads
- json_encode = simplejson.dumps
- JsonDecodeError = ValueError
- JsonEncodeError = TypeError
-
-
-llsd_parsers = {
- 'application/json': json_decode,
- llsd.BINARY_MIME_TYPE: llsd.parse_binary,
- 'application/llsd+notation': llsd.parse_notation,
- llsd.XML_MIME_TYPE: llsd.parse_xml,
- 'application/xml': llsd.parse_xml,
- }
-
-
-def mime_type(content_type):
- '''Given a Content-Type header, return only the MIME type.'''
-
- return content_type.split(';', 1)[0].strip().lower()
-
-class BodyLLSD(object):
- '''Give a webob Request or Response an llsd based "content" property.
-
- Getting the content property parses the body, and caches the result.
-
- Setting the content property formats a payload, and the body property
- is set.'''
-
- def _llsd__get(self):
- '''Get, set, or delete the LLSD value stored in this object.'''
-
- try:
- return self._llsd
- except AttributeError:
- if not self.body:
- raise AttributeError('No llsd attribute has been set')
- else:
- mtype = mime_type(self.content_type)
- try:
- parser = llsd_parsers[mtype]
- except KeyError:
- raise exc.HTTPUnsupportedMediaType(
- 'Content type %s not supported' % mtype).exception
- try:
- self._llsd = parser(self.body)
- except (llsd.LLSDParseError, JsonDecodeError, TypeError), err:
- raise exc.HTTPBadRequest(
- 'Could not parse body: %r' % err.args).exception
- return self._llsd
-
- def _llsd__set(self, val):
- req = getattr(self, 'request', None)
- if req is not None:
- formatter, ctype = formatter_for_request(req)
- self.content_type = ctype
- else:
- formatter, ctype = formatter_for_mime_type(
- mime_type(self.content_type))
- self.body = formatter(val)
-
- def _llsd__del(self):
- if hasattr(self, '_llsd'):
- del self._llsd
-
- content = property(_llsd__get, _llsd__set, _llsd__del)
-
-
-class Response(webob.Response, BodyLLSD):
- '''Response class with LLSD support.
-
- A sensible default content type is used.
-
- Setting the llsd property also sets the body. Getting the llsd
- property parses the body if necessary.
-
- If you set the body property directly, the llsd property will be
- deleted.'''
-
- default_content_type = 'application/llsd+xml'
-
- def _body__set(self, body):
- if hasattr(self, '_llsd'):
- del self._llsd
- super(Response, self)._body__set(body)
-
- def cache_forever(self):
- self.cache_expires(86400 * 365)
-
- body = property(webob.Response._body__get, _body__set,
- webob.Response._body__del,
- webob.Response._body__get.__doc__)
-
-
-class Request(webob.Request, BodyLLSD):
- '''Request class with LLSD support.
-
- Sensible content type and accept headers are used by default.
-
- Setting the content property also sets the body. Getting the content
- property parses the body if necessary.
-
- If you set the body property directly, the content property will be
- deleted.'''
-
- default_content_type = 'application/llsd+xml'
- default_accept = ('application/llsd+xml; q=0.5, '
- 'application/llsd+notation; q=0.3, '
- 'application/llsd+binary; q=0.2, '
- 'application/xml; q=0.1, '
- 'application/json; q=0.0')
-
- def __init__(self, environ=None, *args, **kwargs):
- if environ is None:
- environ = {}
- else:
- environ = environ.copy()
- if 'CONTENT_TYPE' not in environ:
- environ['CONTENT_TYPE'] = self.default_content_type
- if 'HTTP_ACCEPT' not in environ:
- environ['HTTP_ACCEPT'] = self.default_accept
- super(Request, self).__init__(environ, *args, **kwargs)
-
- def _body__set(self, body):
- if hasattr(self, '_llsd'):
- del self._llsd
- super(Request, self)._body__set(body)
-
- def path_urljoin(self, *parts):
- return '/'.join([path_url.rstrip('/')] + list(parts))
-
- body = property(webob.Request._body__get, _body__set,
- webob.Request._body__del, webob.Request._body__get.__doc__)
-
- def create_response(self, content=None, status='200 OK',
- conditional_response=webob.NoDefault):
- resp = self.ResponseClass(status=status, request=self,
- conditional_response=conditional_response)
- resp.content = content
- return resp
-
- def curl(self):
- '''Create and fill out a pycurl easy object from this request.'''
-
- import pycurl
- c = pycurl.Curl()
- c.setopt(pycurl.URL, self.url())
- if self.headers:
- c.setopt(pycurl.HTTPHEADER,
- ['%s: %s' % (k, self.headers[k]) for k in self.headers])
- c.setopt(pycurl.FOLLOWLOCATION, True)
- c.setopt(pycurl.AUTOREFERER, True)
- c.setopt(pycurl.MAXREDIRS, 16)
- c.setopt(pycurl.NOSIGNAL, True)
- c.setopt(pycurl.READFUNCTION, self.body_file.read)
- c.setopt(pycurl.SSL_VERIFYHOST, 2)
-
- if self.method == 'POST':
- c.setopt(pycurl.POST, True)
- post301 = getattr(pycurl, 'POST301', None)
- if post301 is not None:
- # Added in libcurl 7.17.1.
- c.setopt(post301, True)
- elif self.method == 'PUT':
- c.setopt(pycurl.PUT, True)
- elif self.method != 'GET':
- c.setopt(pycurl.CUSTOMREQUEST, self.method)
- return c
-
-Request.ResponseClass = Response
-Response.RequestClass = Request
-
-
-llsd_formatters = {
- 'application/json': json_encode,
- 'application/llsd+binary': llsd.format_binary,
- 'application/llsd+notation': llsd.format_notation,
- 'application/llsd+xml': llsd.format_xml,
- 'application/xml': llsd.format_xml,
- }
-
-formatter_qualities = (
- ('application/llsd+xml', 1.0),
- ('application/llsd+notation', 0.5),
- ('application/llsd+binary', 0.4),
- ('application/xml', 0.3),
- ('application/json', 0.2),
- )
-
-def formatter_for_mime_type(mime_type):
- '''Return a formatter that encodes to the given MIME type.
-
- The result is a pair of function and MIME type.'''
- try:
- return llsd_formatters[mime_type], mime_type
- except KeyError:
- raise exc.HTTPInternalServerError(
- 'Could not use MIME type %r to format response' %
- mime_type).exception
-
-
-def formatter_for_request(req):
- '''Return a formatter that encodes to the preferred type of the client.
-
- The result is a pair of function and actual MIME type.'''
- ctype = req.accept.best_match(formatter_qualities)
- try:
- return llsd_formatters[ctype], ctype
- except KeyError:
- raise exc.HTTPNotAcceptable().exception
-
-
-def wsgi_adapter(func, environ, start_response):
- '''Adapt a Siesta callable to act as a WSGI application.'''
- # Process the request as appropriate.
- try:
- req = Request(environ)
- #print req.urlvars
- resp = func(req, **req.urlvars)
- if not isinstance(resp, webob.Response):
- try:
- formatter, ctype = formatter_for_request(req)
- resp = req.ResponseClass(formatter(resp), content_type=ctype)
- resp._llsd = resp
- except (JsonEncodeError, TypeError), err:
- resp = exc.HTTPInternalServerError(
- detail='Could not format response')
- except exc.HTTPException, e:
- resp = e
- except socket.error, e:
- resp = exc.HTTPInternalServerError(detail=e.args[1])
- return resp(environ, start_response)
-
-
-def llsd_callable(func):
- '''Turn a callable into a Siesta application.'''
-
- def replacement(environ, start_response):
- return wsgi_adapter(func, environ, start_response)
-
- return replacement
-
-
-def llsd_method(http_method, func):
- def replacement(environ, start_response):
- if environ['REQUEST_METHOD'] == http_method:
- return wsgi_adapter(func, environ, start_response)
- return exc.HTTPMethodNotAllowed()(environ, start_response)
-
- return replacement
-
-
-http11_methods = 'OPTIONS GET HEAD POST PUT DELETE TRACE CONNECT'.split()
-http11_methods.sort()
-
-def llsd_class(cls):
- '''Turn a class into a Siesta application.
-
- A new instance is created for each request. A HTTP method FOO is
- turned into a call to the handle_foo method of the instance.'''
-
- def foo(req, **kwargs):
- instance = cls()
- method = req.method.lower()
- try:
- handler = getattr(instance, 'handle_' + method)
- except AttributeError:
- allowed = [m for m in http11_methods
- if hasattr(instance, 'handle_' + m.lower())]
- raise exc.HTTPMethodNotAllowed(
- headers={'Allow': ', '.join(allowed)}).exception
- #print "kwargs: ", kwargs
- return handler(req, **kwargs)
-
- def replacement(environ, start_response):
- return wsgi_adapter(foo, environ, start_response)
-
- return replacement
-
-
-def curl(reqs):
- import pycurl
-
- m = pycurl.CurlMulti()
- curls = [r.curl() for r in reqs]
- io = {}
- for c in curls:
- fp = StringIO()
- hdr = StringIO()
- c.setopt(pycurl.WRITEFUNCTION, fp.write)
- c.setopt(pycurl.HEADERFUNCTION, hdr.write)
- io[id(c)] = fp, hdr
- m.handles = curls
- try:
- while True:
- ret, num_handles = m.perform()
- if ret != pycurl.E_CALL_MULTI_PERFORM:
- break
- finally:
- m.close()
-
- for req, c in zip(reqs, curls):
- fp, hdr = io[id(c)]
- hdr.seek(0)
- status = hdr.readline().rstrip()
- headers = []
- name, values = None, None
-
- # XXX We don't currently handle bogus header data.
-
- for line in hdr.readlines():
- if not line[0].isspace():
- if name:
- headers.append((name, ' '.join(values)))
- name, value = line.strip().split(':', 1)
- value = [value]
- else:
- values.append(line.strip())
- if name:
- headers.append((name, ' '.join(values)))
-
- resp = c.ResponseClass(fp.getvalue(), status, headers, request=req)
-
-
-route_re = re.compile(r'''
- \{ # exact character "{"
- (\w*) # "config" or variable (restricted to a-z, 0-9, _)
- (?:([:~])([^}]+))? # optional :type or ~regex part
- \} # exact character "}"
- ''', re.VERBOSE)
-
-predefined_regexps = {
- 'uuid': r'[a-f0-9][a-f0-9-]{31,35}',
- 'int': r'\d+',
- 'host': r'[a-z0-9][a-z0-9\-\.]*',
- }
-
-def compile_route(route):
- fp = StringIO()
- last_pos = 0
- for match in route_re.finditer(route):
- #print "matches: ", match.groups()
- fp.write(re.escape(route[last_pos:match.start()]))
- var_name = match.group(1)
- sep = match.group(2)
- expr = match.group(3)
- if var_name == 'config':
- expr = re.escape(str(config.get(var_name)))
- else:
- if expr:
- if sep == ':':
- expr = predefined_regexps[expr]
- # otherwise, treat what follows '~' as a regexp
- else:
- expr = '[^/]+'
- if var_name != '':
- expr = '(?P<%s>%s)' % (var_name, expr)
- else:
- expr = '(%s)' % (expr,)
- fp.write(expr)
- last_pos = match.end()
- fp.write(re.escape(route[last_pos:]))
- compiled_route = '^%s$' % fp.getvalue()
- #print route, "->", compiled_route
- return compiled_route
-
-class Router(object):
- '''WSGI routing class. Parses a URL and hands off a request to
- some other WSGI application. If no suitable application is found,
- responds with a 404.'''
-
- def __init__(self):
- self._new_routes = []
- self._routes = []
- self._paths = []
-
- def add(self, route, app, methods=None):
- self._new_routes.append((route, app, methods))
-
- def _create_routes(self):
- for route, app, methods in self._new_routes:
- self._paths.append(route)
- self._routes.append(
- (re.compile(compile_route(route)),
- app,
- methods and dict.fromkeys(methods)))
- self._new_routes = []
-
- def __call__(self, environ, start_response):
- # load up the config from the config file. Only needs to be
- # done once per interpreter. This is the entry point of all
- # siesta applications, so this is where we trap it.
- _conf = config.get_config()
- if _conf is None:
- import os.path
- fname = os.path.join(
- environ.get('ll.config_dir', '/local/linden/etc'),
- 'indra.xml')
- config.load(fname)
-
- # proceed with handling the request
- self._create_routes()
- path_info = environ['PATH_INFO']
- request_method = environ['REQUEST_METHOD']
- allowed = []
- for regex, app, methods in self._routes:
- m = regex.match(path_info)
- if m:
- #print "groupdict:",m.groupdict()
- if not methods or request_method in methods:
- environ['paste.urlvars'] = m.groupdict()
- return app(environ, start_response)
- else:
- allowed += methods
- if allowed:
- allowed = dict.fromkeys(allows).keys()
- allowed.sort()
- resp = exc.HTTPMethodNotAllowed(
- headers={'Allow': ', '.join(allowed)})
- else:
- resp = exc.HTTPNotFound()
- return resp(environ, start_response)
diff --git a/indra/lib/python/indra/ipc/siesta_test.py b/indra/lib/python/indra/ipc/siesta_test.py
deleted file mode 100644
index 177ea710d1..0000000000
--- a/indra/lib/python/indra/ipc/siesta_test.py
+++ /dev/null
@@ -1,214 +0,0 @@
-from indra.base import llsd, lluuid
-from indra.ipc import siesta
-import datetime, math, unittest
-from webob import exc
-
-
-class ClassApp(object):
- def handle_get(self, req):
- pass
-
- def handle_post(self, req):
- return req.llsd
-
-
-def callable_app(req):
- if req.method == 'UNDERPANTS':
- raise exc.HTTPMethodNotAllowed()
- elif req.method == 'GET':
- return None
- return req.llsd
-
-
-class TestBase:
- def test_basic_get(self):
- req = siesta.Request.blank('/')
- self.assertEquals(req.get_response(self.server).body,
- llsd.format_xml(None))
-
- def test_bad_method(self):
- req = siesta.Request.blank('/')
- req.environ['REQUEST_METHOD'] = 'UNDERPANTS'
- self.assertEquals(req.get_response(self.server).status_int,
- exc.HTTPMethodNotAllowed.code)
-
- json_safe = {
- 'none': None,
- 'bool_true': True,
- 'bool_false': False,
- 'int_zero': 0,
- 'int_max': 2147483647,
- 'int_min': -2147483648,
- 'long_zero': 0,
- 'long_max': 2147483647L,
- 'long_min': -2147483648L,
- 'float_zero': 0,
- 'float': math.pi,
- 'float_huge': 3.14159265358979323846e299,
- 'str_empty': '',
- 'str': 'foo',
- u'unic\u1e51de_empty': u'',
- u'unic\u1e51de': u'\u1e4exx\u10480',
- }
- json_safe['array'] = json_safe.values()
- json_safe['tuple'] = tuple(json_safe.values())
- json_safe['dict'] = json_safe.copy()
-
- json_unsafe = {
- 'uuid_empty': lluuid.UUID(),
- 'uuid_full': lluuid.UUID('dc61ab0530200d7554d23510559102c1a98aab1b'),
- 'binary_empty': llsd.binary(),
- 'binary': llsd.binary('f\0\xff'),
- 'uri_empty': llsd.uri(),
- 'uri': llsd.uri('http://www.secondlife.com/'),
- 'datetime_empty': datetime.datetime(1970,1,1),
- 'datetime': datetime.datetime(1999,9,9,9,9,9),
- }
- json_unsafe.update(json_safe)
- json_unsafe['array'] = json_unsafe.values()
- json_unsafe['tuple'] = tuple(json_unsafe.values())
- json_unsafe['dict'] = json_unsafe.copy()
- json_unsafe['iter'] = iter(json_unsafe.values())
-
- def _test_client_content_type_good(self, content_type, ll):
- def run(ll):
- req = siesta.Request.blank('/')
- req.environ['REQUEST_METHOD'] = 'POST'
- req.content_type = content_type
- req.llsd = ll
- req.accept = content_type
- resp = req.get_response(self.server)
- self.assertEquals(resp.status_int, 200)
- return req, resp
-
- if False and isinstance(ll, dict):
- def fixup(v):
- if isinstance(v, float):
- return '%.5f' % v
- if isinstance(v, long):
- return int(v)
- if isinstance(v, (llsd.binary, llsd.uri)):
- return v
- if isinstance(v, (tuple, list)):
- return [fixup(i) for i in v]
- if isinstance(v, dict):
- return dict([(k, fixup(i)) for k, i in v.iteritems()])
- return v
- for k, v in ll.iteritems():
- l = [k, v]
- req, resp = run(l)
- self.assertEquals(fixup(resp.llsd), fixup(l))
-
- run(ll)
-
- def test_client_content_type_json_good(self):
- self._test_client_content_type_good('application/json', self.json_safe)
-
- def test_client_content_type_llsd_xml_good(self):
- self._test_client_content_type_good('application/llsd+xml',
- self.json_unsafe)
-
- def test_client_content_type_llsd_notation_good(self):
- self._test_client_content_type_good('application/llsd+notation',
- self.json_unsafe)
-
- def test_client_content_type_llsd_binary_good(self):
- self._test_client_content_type_good('application/llsd+binary',
- self.json_unsafe)
-
- def test_client_content_type_xml_good(self):
- self._test_client_content_type_good('application/xml',
- self.json_unsafe)
-
- def _test_client_content_type_bad(self, content_type):
- req = siesta.Request.blank('/')
- req.environ['REQUEST_METHOD'] = 'POST'
- req.body = '\0invalid nonsense under all encodings'
- req.content_type = content_type
- self.assertEquals(req.get_response(self.server).status_int,
- exc.HTTPBadRequest.code)
-
- def test_client_content_type_json_bad(self):
- self._test_client_content_type_bad('application/json')
-
- def test_client_content_type_llsd_xml_bad(self):
- self._test_client_content_type_bad('application/llsd+xml')
-
- def test_client_content_type_llsd_notation_bad(self):
- self._test_client_content_type_bad('application/llsd+notation')
-
- def test_client_content_type_llsd_binary_bad(self):
- self._test_client_content_type_bad('application/llsd+binary')
-
- def test_client_content_type_xml_bad(self):
- self._test_client_content_type_bad('application/xml')
-
- def test_client_content_type_bad(self):
- req = siesta.Request.blank('/')
- req.environ['REQUEST_METHOD'] = 'POST'
- req.body = 'XXX'
- req.content_type = 'application/nonsense'
- self.assertEquals(req.get_response(self.server).status_int,
- exc.HTTPUnsupportedMediaType.code)
-
- def test_request_default_content_type(self):
- req = siesta.Request.blank('/')
- self.assertEquals(req.content_type, req.default_content_type)
-
- def test_request_default_accept(self):
- req = siesta.Request.blank('/')
- from webob import acceptparse
- self.assertEquals(str(req.accept).replace(' ', ''),
- req.default_accept.replace(' ', ''))
-
- def test_request_llsd_auto_body(self):
- req = siesta.Request.blank('/')
- req.llsd = {'a': 2}
- self.assertEquals(req.body, '')
-
- def test_request_llsd_mod_body_changes_llsd(self):
- req = siesta.Request.blank('/')
- req.llsd = {'a': 2}
- req.body = '1337'
- self.assertEquals(req.llsd, 1337)
-
- def test_request_bad_llsd_fails(self):
- def crashme(ctype):
- def boom():
- class foo(object): pass
- req = siesta.Request.blank('/')
- req.content_type = ctype
- req.llsd = foo()
- for mime_type in siesta.llsd_parsers:
- self.assertRaises(TypeError, crashme(mime_type))
-
-
-class ClassServer(TestBase, unittest.TestCase):
- def __init__(self, *args, **kwargs):
- unittest.TestCase.__init__(self, *args, **kwargs)
- self.server = siesta.llsd_class(ClassApp)
-
-
-class CallableServer(TestBase, unittest.TestCase):
- def __init__(self, *args, **kwargs):
- unittest.TestCase.__init__(self, *args, **kwargs)
- self.server = siesta.llsd_callable(callable_app)
-
-
-class RouterServer(unittest.TestCase):
- def test_router(self):
- def foo(req, quux):
- print quux
-
- r = siesta.Router()
- r.add('/foo/{quux:int}', siesta.llsd_callable(foo), methods=['GET'])
- req = siesta.Request.blank('/foo/33')
- req.get_response(r)
-
- req = siesta.Request.blank('/foo/bar')
- self.assertEquals(req.get_response(r).status_int,
- exc.HTTPNotFound.code)
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/indra/lib/python/indra/ipc/webdav.py b/indra/lib/python/indra/ipc/webdav.py
deleted file mode 100644
index 98b8499b6a..0000000000
--- a/indra/lib/python/indra/ipc/webdav.py
+++ /dev/null
@@ -1,597 +0,0 @@
-"""
-@file webdav.py
-@brief Classes to make manipulation of a webdav store easier.
-
-$LicenseInfo:firstyear=2007&license=mit$
-
-Copyright (c) 2007-2009, Linden Research, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-$/LicenseInfo$
-"""
-
-import sys, os, httplib, urlparse
-import socket, time
-import xml.dom.minidom
-import syslog
-# import signal
-
-__revision__ = '0'
-
-dav_debug = False
-
-
-# def urlsafe_b64decode (enc):
-# return base64.decodestring (enc.replace ('_', '/').replace ('-', '+'))
-
-# def urlsafe_b64encode (str):
-# return base64.encodestring (str).replace ('+', '-').replace ('/', '_')
-
-
-class DAVError (Exception):
- """ Base class for exceptions in this module. """
- def __init__ (self, status=0, message='', body='', details=''):
- self.status = status
- self.message = message
- self.body = body
- self.details = details
- Exception.__init__ (self, '%d:%s:%s%s' % (self.status, self.message,
- self.body, self.details))
-
- def print_to_stderr (self):
- """ print_to_stderr docstring """
- print >> sys.stderr, str (self.status) + ' ' + self.message
- print >> sys.stderr, str (self.details)
-
-
-class Timeout (Exception):
- """ Timeout docstring """
- def __init__ (self, arg=''):
- Exception.__init__ (self, arg)
-
-
-def alarm_handler (signum, frame):
- """ alarm_handler docstring """
- raise Timeout ('caught alarm')
-
-
-class WebDAV:
- """ WebDAV docstring """
- def __init__ (self, url, proxy=None, retries_before_fail=6):
- self.init_url = url
- self.init_proxy = proxy
- self.retries_before_fail = retries_before_fail
- url_parsed = urlparse.urlsplit (url)
-
- self.top_path = url_parsed[ 2 ]
- # make sure top_path has a trailing /
- if self.top_path == None or self.top_path == '':
- self.top_path = '/'
- elif len (self.top_path) > 1 and self.top_path[-1:] != '/':
- self.top_path += '/'
-
- if dav_debug:
- syslog.syslog ('new WebDAV %s : %s' % (str (url), str (proxy)))
-
- if proxy:
- proxy_parsed = urlparse.urlsplit (proxy)
- self.host_header = url_parsed[ 1 ]
- host_and_port = proxy_parsed[ 1 ].split (':')
- self.host = host_and_port[ 0 ]
- if len (host_and_port) > 1:
- self.port = int(host_and_port[ 1 ])
- else:
- self.port = 80
- else: # no proxy
- host_and_port = url_parsed[ 1 ].split (':')
- self.host_header = None
- self.host = host_and_port[ 0 ]
- if len (host_and_port) > 1:
- self.port = int(host_and_port[ 1 ])
- else:
- self.port = 80
-
- self.connection = False
- self.connect ()
-
-
- def log (self, msg, depth=0):
- """ log docstring """
- if dav_debug and depth == 0:
- host = str (self.init_url)
- if host == 'http://int.tuco.lindenlab.com:80/asset/':
- host = 'tuco'
- if host == 'http://harriet.lindenlab.com/asset-keep/':
- host = 'harriet/asset-keep'
- if host == 'http://harriet.lindenlab.com/asset-flag/':
- host = 'harriet/asset-flag'
- if host == 'http://harriet.lindenlab.com/asset/':
- host = 'harriet/asset'
- if host == 'http://ozzy.lindenlab.com/asset/':
- host = 'ozzy/asset'
- if host == 'http://station11.lindenlab.com:12041/:':
- host = 'station11:12041'
- proxy = str (self.init_proxy)
- if proxy == 'None':
- proxy = ''
- if proxy == 'http://int.tuco.lindenlab.com:3128/':
- proxy = 'tuco'
- syslog.syslog ('WebDAV (%s:%s) %s' % (host, proxy, str (msg)))
-
-
- def connect (self):
- """ connect docstring """
- self.log ('connect')
- self.connection = httplib.HTTPConnection (self.host, self.port)
-
- def __err (self, response, details):
- """ __err docstring """
- raise DAVError (response.status, response.reason, response.read (),
- str (self.init_url) + ':' + \
- str (self.init_proxy) + ':' + str (details))
-
- def request (self, method, path, body=None, headers=None,
- read_all=True, body_hook = None, recurse=0, allow_cache=True):
- """ request docstring """
- # self.log ('request %s %s' % (method, path))
- if headers == None:
- headers = {}
- if not allow_cache:
- headers['Pragma'] = 'no-cache'
- headers['cache-control'] = 'no-cache'
- try:
- if method.lower () != 'purge':
- if path.startswith ('/'):
- path = path[1:]
- if self.host_header: # use proxy
- headers[ 'host' ] = self.host_header
- fullpath = 'http://%s%s%s' % (self.host_header,
- self.top_path, path)
- else: # no proxy
- fullpath = self.top_path + path
- else:
- fullpath = path
-
- self.connection.request (method, fullpath, body, headers)
- if body_hook:
- body_hook ()
-
- # signal.signal (signal.SIGALRM, alarm_handler)
- # try:
- # signal.alarm (120)
- # signal.alarm (0)
- # except Timeout, e:
- # if recurse < 6:
- # return self.retry_request (method, path, body, headers,
- # read_all, body_hook, recurse)
- # else:
- # raise DAVError (0, 'timeout', self.host,
- # (method, path, body, headers, recurse))
-
- response = self.connection.getresponse ()
-
- if read_all:
- while len (response.read (1024)) > 0:
- pass
- if (response.status == 500 or \
- response.status == 503 or \
- response.status == 403) and \
- recurse < self.retries_before_fail:
- return self.retry_request (method, path, body, headers,
- read_all, body_hook, recurse)
- return response
- except (httplib.ResponseNotReady,
- httplib.BadStatusLine,
- socket.error):
- # if the server hangs up on us (keepalive off, broken pipe),
- # we need to reconnect and try again.
- if recurse < self.retries_before_fail:
- return self.retry_request (method, path, body, headers,
- read_all, body_hook, recurse)
- raise DAVError (0, 'reconnect failed', self.host,
- (method, path, body, headers, recurse))
-
-
- def retry_request (self, method, path, body, headers,
- read_all, body_hook, recurse):
- """ retry_request docstring """
- time.sleep (10.0 * recurse)
- self.connect ()
- return self.request (method, path, body, headers,
- read_all, body_hook, recurse+1)
-
-
-
- def propfind (self, path, body=None, depth=1):
- """ propfind docstring """
- # self.log ('propfind %s' % path)
- headers = {'Content-Type':'text/xml; charset="utf-8"',
- 'Depth':str(depth)}
- response = self.request ('PROPFIND', path, body, headers, False)
- if response.status == 207:
- return response # Multi-Status
- self.__err (response, ('PROPFIND', path, body, headers, 0))
-
-
- def purge (self, path):
- """ issue a squid purge command """
- headers = {'Accept':'*/*'}
- response = self.request ('PURGE', path, None, headers)
- if response.status == 200 or response.status == 404:
- # 200 if it was purge, 404 if it wasn't there.
- return response
- self.__err (response, ('PURGE', path, None, headers))
-
-
- def get_file_size (self, path):
- """
- Use propfind to ask a webdav server what the size of
- a file is. If used on a directory (collection) return 0
- """
- self.log ('get_file_size %s' % path)
- # "getcontentlength" property
- # 8.1.1 Example - Retrieving Named Properties
- # http://docs.python.org/lib/module-xml.dom.html
- nsurl = 'http://apache.org/dav/props/'
- doc = xml.dom.minidom.Document ()
- propfind_element = doc.createElementNS (nsurl, "D:propfind")
- propfind_element.setAttributeNS (nsurl, 'xmlns:D', 'DAV:')
- doc.appendChild (propfind_element)
- prop_element = doc.createElementNS (nsurl, "D:prop")
- propfind_element.appendChild (prop_element)
- con_len_element = doc.createElementNS (nsurl, "D:getcontentlength")
- prop_element.appendChild (con_len_element)
-
- response = self.propfind (path, doc.toxml ())
- doc.unlink ()
-
- resp_doc = xml.dom.minidom.parseString (response.read ())
- cln = resp_doc.getElementsByTagNameNS ('DAV:','getcontentlength')[ 0 ]
- try:
- content_length = int (cln.childNodes[ 0 ].nodeValue)
- except IndexError:
- return 0
- resp_doc.unlink ()
- return content_length
-
-
- def file_exists (self, path):
- """
- do an http head on the given file. return True if it succeeds
- """
- self.log ('file_exists %s' % path)
- expect_gzip = path.endswith ('.gz')
- response = self.request ('HEAD', path)
- got_gzip = response.getheader ('Content-Encoding', '').strip ()
- if got_gzip.lower () == 'x-gzip' and expect_gzip == False:
- # the asset server fakes us out if we ask for the non-gzipped
- # version of an asset, but the server has the gzipped version.
- return False
- return response.status == 200
-
-
- def mkdir (self, path):
- """ mkdir docstring """
- self.log ('mkdir %s' % path)
- headers = {}
- response = self.request ('MKCOL', path, None, headers)
- if response.status == 201:
- return # success
- if response.status == 405:
- return # directory already existed?
- self.__err (response, ('MKCOL', path, None, headers, 0))
-
-
- def delete (self, path):
- """ delete docstring """
- self.log ('delete %s' % path)
- headers = {'Depth':'infinity'} # collections require infinity
- response = self.request ('DELETE', path, None, headers)
- if response.status == 204:
- return # no content
- if response.status == 404:
- return # hmm
- self.__err (response, ('DELETE', path, None, headers, 0))
-
-
- def list_directory (self, path, dir_filter=None, allow_cache=True,
- minimum_cache_time=False):
- """
- Request an http directory listing and parse the filenames out of lines
- like: ' X'. If a filter function is provided,
- only return filenames that the filter returns True for.
-
- This is sort of grody, but it seems faster than other ways of getting
- this information from an isilon.
- """
- self.log ('list_directory %s' % path)
-
- def try_match (lline, before, after):
- """ try_match docstring """
- try:
- blen = len (before)
- asset_start_index = lline.index (before)
- asset_end_index = lline.index (after, asset_start_index + blen)
- asset = line[ asset_start_index + blen : asset_end_index ]
-
- if not dir_filter or dir_filter (asset):
- return [ asset ]
- return []
- except ValueError:
- return []
-
- if len (path) > 0 and path[-1:] != '/':
- path += '/'
-
- response = self.request ('GET', path, None, {}, False,
- allow_cache=allow_cache)
-
- if allow_cache and minimum_cache_time: # XXX
- print response.getheader ('Date')
- # s = "2005-12-06T12:13:14"
- # from datetime import datetime
- # from time import strptime
- # datetime(*strptime(s, "%Y-%m-%dT%H:%M:%S")[0:6])
- # datetime.datetime(2005, 12, 6, 12, 13, 14)
-
- if response.status != 200:
- self.__err (response, ('GET', path, None, {}, 0))
- assets = []
- for line in response.read ().split ('\n'):
- lline = line.lower ()
- if lline.find ("parent directory") == -1:
- # isilon file
- assets += try_match (lline, ' ')
- # apache dir
- assets += try_match (lline, 'alt="[dir]"> ')
- # apache file
- assets += try_match (lline, 'alt="[ ]"> ')
- return assets
-
-
- def __tmp_filename (self, path_and_file):
- """ __tmp_filename docstring """
- head, tail = os.path.split (path_and_file)
- if head != '':
- return head + '/.' + tail + '.' + str (os.getpid ())
- else:
- return head + '.' + tail + '.' + str (os.getpid ())
-
-
- def __put__ (self, filesize, body_hook, remotefile):
- """ __put__ docstring """
- headers = {'Content-Length' : str (filesize)}
- remotefile_tmp = self.__tmp_filename (remotefile)
- response = self.request ('PUT', remotefile_tmp, None,
- headers, True, body_hook)
- if not response.status in (201, 204): # created, no content
- self.__err (response, ('PUT', remotefile, None, headers, 0))
- if filesize != self.get_file_size (remotefile_tmp):
- try:
- self.delete (remotefile_tmp)
- except:
- pass
- raise DAVError (0, 'tmp upload error', remotefile_tmp)
- # move the file to its final location
- try:
- self.rename (remotefile_tmp, remotefile)
- except DAVError, exc:
- if exc.status == 403: # try to clean up the tmp file
- try:
- self.delete (remotefile_tmp)
- except:
- pass
- raise
- if filesize != self.get_file_size (remotefile):
- raise DAVError (0, 'file upload error', str (remotefile_tmp))
-
-
- def put_string (self, strng, remotefile):
- """ put_string docstring """
- self.log ('put_string %d -> %s' % (len (strng), remotefile))
- filesize = len (strng)
- def body_hook ():
- """ body_hook docstring """
- self.connection.send (strng)
- self.__put__ (filesize, body_hook, remotefile)
-
-
- def put_file (self, localfile, remotefile):
- """
- Send a local file to a remote webdav store. First, upload to
- a temporary filename. Next make sure the file is the size we
- expected. Next, move the file to its final location. Next,
- check the file size at the final location.
- """
- self.log ('put_file %s -> %s' % (localfile, remotefile))
- filesize = os.path.getsize (localfile)
- def body_hook ():
- """ body_hook docstring """
- handle = open (localfile)
- while True:
- data = handle.read (1300)
- if len (data) == 0:
- break
- self.connection.send (data)
- handle.close ()
- self.__put__ (filesize, body_hook, remotefile)
-
-
- def create_empty_file (self, remotefile):
- """ create an empty file """
- self.log ('touch_file %s' % (remotefile))
- headers = {'Content-Length' : '0'}
- response = self.request ('PUT', remotefile, None, headers)
- if not response.status in (201, 204): # created, no content
- self.__err (response, ('PUT', remotefile, None, headers, 0))
- if self.get_file_size (remotefile) != 0:
- raise DAVError (0, 'file upload error', str (remotefile))
-
-
- def __get_file_setup (self, remotefile, check_size=True):
- """ __get_file_setup docstring """
- if check_size:
- remotesize = self.get_file_size (remotefile)
- response = self.request ('GET', remotefile, None, {}, False)
- if response.status != 200:
- self.__err (response, ('GET', remotefile, None, {}, 0))
- try:
- content_length = int (response.getheader ("Content-Length"))
- except TypeError:
- content_length = None
- if check_size:
- if content_length != remotesize:
- raise DAVError (0, 'file DL size error', remotefile)
- return (response, content_length)
-
-
- def __get_file_read (self, writehandle, response, content_length):
- """ __get_file_read docstring """
- if content_length != None:
- so_far_length = 0
- while so_far_length < content_length:
- data = response.read (content_length - so_far_length)
- if len (data) == 0:
- raise DAVError (0, 'short file download')
- so_far_length += len (data)
- writehandle.write (data)
- while len (response.read ()) > 0:
- pass
- else:
- while True:
- data = response.read ()
- if (len (data) < 1):
- break
- writehandle.write (data)
-
-
- def get_file (self, remotefile, localfile, check_size=True):
- """
- Get a remote file from a webdav server. Download to a local
- tmp file, then move into place. Sanity check file sizes as
- we go.
- """
- self.log ('get_file %s -> %s' % (remotefile, localfile))
- (response, content_length) = \
- self.__get_file_setup (remotefile, check_size)
- localfile_tmp = self.__tmp_filename (localfile)
- handle = open (localfile_tmp, 'w')
- self.__get_file_read (handle, response, content_length)
- handle.close ()
- if check_size:
- if content_length != os.path.getsize (localfile_tmp):
- raise DAVError (0, 'file DL size error',
- remotefile+','+localfile)
- os.rename (localfile_tmp, localfile)
-
-
- def get_file_as_string (self, remotefile, check_size=True):
- """
- download a file from a webdav server and return it as a string.
- """
- self.log ('get_file_as_string %s' % remotefile)
- (response, content_length) = \
- self.__get_file_setup (remotefile, check_size)
- # (tmp_handle, tmp_filename) = tempfile.mkstemp ()
- tmp_handle = os.tmpfile ()
- self.__get_file_read (tmp_handle, response, content_length)
- tmp_handle.seek (0)
- ret = tmp_handle.read ()
- tmp_handle.close ()
- # os.unlink (tmp_filename)
- return ret
-
-
- def get_post_as_string (self, remotefile, body):
- """
- Do an http POST, send body, get response and return it.
- """
- self.log ('get_post_as_string %s' % remotefile)
- # headers = {'Content-Type':'application/x-www-form-urlencoded'}
- headers = {'Content-Type':'text/xml; charset="utf-8"'}
- # b64body = urlsafe_b64encode (asset_url)
- response = self.request ('POST', remotefile, body, headers, False)
- if response.status != 200:
- self.__err (response, ('POST', remotefile, body, headers, 0))
- try:
- content_length = int (response.getheader ('Content-Length'))
- except TypeError:
- content_length = None
- tmp_handle = os.tmpfile ()
- self.__get_file_read (tmp_handle, response, content_length)
- tmp_handle.seek (0)
- ret = tmp_handle.read ()
- tmp_handle.close ()
- return ret
-
-
- def __destination_command (self, verb, remotesrc, dstdav, remotedst):
- """
- self and dstdav should point to the same http server.
- """
- if len (remotedst) > 0 and remotedst[ 0 ] == '/':
- remotedst = remotedst[1:]
- headers = {'Destination': 'http://%s:%d%s%s' % (dstdav.host,
- dstdav.port,
- dstdav.top_path,
- remotedst)}
- response = self.request (verb, remotesrc, None, headers)
- if response.status == 201:
- return # created
- if response.status == 204:
- return # no content
- self.__err (response, (verb, remotesrc, None, headers, 0))
-
-
- def rename (self, remotesrc, remotedst):
- """ rename a file on a webdav server """
- self.log ('rename %s -> %s' % (remotesrc, remotedst))
- self.__destination_command ('MOVE', remotesrc, self, remotedst)
- def xrename (self, remotesrc, dstdav, remotedst):
- """ rename a file on a webdav server """
- self.log ('xrename %s -> %s' % (remotesrc, remotedst))
- self.__destination_command ('MOVE', remotesrc, dstdav, remotedst)
-
-
- def copy (self, remotesrc, remotedst):
- """ copy a file on a webdav server """
- self.log ('copy %s -> %s' % (remotesrc, remotedst))
- self.__destination_command ('COPY', remotesrc, self, remotedst)
- def xcopy (self, remotesrc, dstdav, remotedst):
- """ copy a file on a webdav server """
- self.log ('xcopy %s -> %s' % (remotesrc, remotedst))
- self.__destination_command ('COPY', remotesrc, dstdav, remotedst)
-
-
-def put_string (data, url):
- """
- upload string s to a url
- """
- url_parsed = urlparse.urlsplit (url)
- dav = WebDAV ('%s://%s/' % (url_parsed[ 0 ], url_parsed[ 1 ]))
- dav.put_string (data, url_parsed[ 2 ])
-
-
-def get_string (url, check_size=True):
- """
- return the contents of a url as a string
- """
- url_parsed = urlparse.urlsplit (url)
- dav = WebDAV ('%s://%s/' % (url_parsed[ 0 ], url_parsed[ 1 ]))
- return dav.get_file_as_string (url_parsed[ 2 ], check_size)
diff --git a/indra/lib/python/indra/ipc/xml_rpc.py b/indra/lib/python/indra/ipc/xml_rpc.py
deleted file mode 100644
index 47536c10c3..0000000000
--- a/indra/lib/python/indra/ipc/xml_rpc.py
+++ /dev/null
@@ -1,273 +0,0 @@
-"""\
-@file xml_rpc.py
-@brief An implementation of a parser/generator for the XML-RPC xml format.
-
-$LicenseInfo:firstyear=2006&license=mit$
-
-Copyright (c) 2006-2009, Linden Research, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-$/LicenseInfo$
-"""
-
-
-from greenlet import greenlet
-
-from mulib import mu
-
-from xml.sax import handler
-from xml.sax import parseString
-
-
-# States
-class Expected(object):
- def __init__(self, tag):
- self.tag = tag
-
- def __getattr__(self, name):
- return type(self)(name)
-
- def __repr__(self):
- return '%s(%r)' % (
- type(self).__name__, self.tag)
-
-
-class START(Expected):
- pass
-
-
-class END(Expected):
- pass
-
-
-class STR(object):
- tag = ''
-
-
-START = START('')
-END = END('')
-
-
-class Malformed(Exception):
- pass
-
-
-class XMLParser(handler.ContentHandler):
- def __init__(self, state_machine, next_states):
- handler.ContentHandler.__init__(self)
- self.state_machine = state_machine
- if not isinstance(next_states, tuple):
- next_states = (next_states, )
- self.next_states = next_states
- self._character_buffer = ''
-
- def assertState(self, state, name, *rest):
- if not isinstance(self.next_states, tuple):
- self.next_states = (self.next_states, )
- for next in self.next_states:
- if type(state) == type(next):
- if next.tag and next.tag != name:
- raise Malformed(
- "Expected %s, got %s %s %s" % (
- next, state, name, rest))
- break
- else:
- raise Malformed(
- "Expected %s, got %s %s %s" % (
- self.next_states, state, name, rest))
-
- def startElement(self, name, attrs):
- self.assertState(START, name.lower(), attrs)
- self.next_states = self.state_machine.switch(START, (name.lower(), dict(attrs)))
-
- def endElement(self, name):
- if self._character_buffer.strip():
- characters = self._character_buffer.strip()
- self._character_buffer = ''
- self.assertState(STR, characters)
- self.next_states = self.state_machine.switch(characters)
- self.assertState(END, name.lower())
- self.next_states = self.state_machine.switch(END, name.lower())
-
- def error(self, exc):
- self.bozo = 1
- self.exc = exc
-
- def fatalError(self, exc):
- self.error(exc)
- raise exc
-
- def characters(self, characters):
- self._character_buffer += characters
-
-
-def parse(what):
- child = greenlet(xml_rpc)
- me = greenlet.getcurrent()
- startup_states = child.switch(me)
- parser = XMLParser(child, startup_states)
- try:
- parseString(what, parser)
- except Malformed:
- print what
- raise
- return child.switch()
-
-
-def xml_rpc(yielder):
- yielder.switch(START.methodcall)
- yielder.switch(START.methodname)
- methodName = yielder.switch(STR)
- yielder.switch(END.methodname)
-
- yielder.switch(START.params)
-
- root = None
- params = []
- while True:
- state, _ = yielder.switch(START.param, END.params)
- if state == END:
- break
-
- yielder.switch(START.value)
-
- params.append(
- handle(yielder))
-
- yielder.switch(END.value)
- yielder.switch(END.param)
-
- yielder.switch(END.methodcall)
- ## Resume parse
- yielder.switch()
- ## Return result to parse
- return methodName.strip(), params
-
-
-def handle(yielder):
- _, (tag, attrs) = yielder.switch(START)
- if tag in ['int', 'i4']:
- result = int(yielder.switch(STR))
- elif tag == 'boolean':
- result = bool(int(yielder.switch(STR)))
- elif tag == 'string':
- result = yielder.switch(STR)
- elif tag == 'double':
- result = float(yielder.switch(STR))
- elif tag == 'datetime.iso8601':
- result = yielder.switch(STR)
- elif tag == 'base64':
- result = base64.b64decode(yielder.switch(STR))
- elif tag == 'struct':
- result = {}
- while True:
- state, _ = yielder.switch(START.member, END.struct)
- if state == END:
- break
-
- yielder.switch(START.name)
- key = yielder.switch(STR)
- yielder.switch(END.name)
-
- yielder.switch(START.value)
- result[key] = handle(yielder)
- yielder.switch(END.value)
-
- yielder.switch(END.member)
- ## We already handled above, don't want to handle it below
- return result
- elif tag == 'array':
- result = []
- yielder.switch(START.data)
- while True:
- state, _ = yielder.switch(START.value, END.data)
- if state == END:
- break
-
- result.append(handle(yielder))
-
- yielder.switch(END.value)
-
- yielder.switch(getattr(END, tag))
-
- return result
-
-
-VALUE = mu.tag_factory('value')
-BOOLEAN = mu.tag_factory('boolean')
-INT = mu.tag_factory('int')
-STRUCT = mu.tag_factory('struct')
-MEMBER = mu.tag_factory('member')
-NAME = mu.tag_factory('name')
-ARRAY = mu.tag_factory('array')
-DATA = mu.tag_factory('data')
-STRING = mu.tag_factory('string')
-DOUBLE = mu.tag_factory('double')
-METHODRESPONSE = mu.tag_factory('methodResponse')
-PARAMS = mu.tag_factory('params')
-PARAM = mu.tag_factory('param')
-
-mu.inline_elements['string'] = True
-mu.inline_elements['boolean'] = True
-mu.inline_elements['name'] = True
-
-
-def _generate(something):
- if isinstance(something, dict):
- result = STRUCT()
- for key, value in something.items():
- result[
- MEMBER[
- NAME[key], _generate(value)]]
- return VALUE[result]
- elif isinstance(something, list):
- result = DATA()
- for item in something:
- result[_generate(item)]
- return VALUE[ARRAY[[result]]]
- elif isinstance(something, basestring):
- return VALUE[STRING[something]]
- elif isinstance(something, bool):
- if something:
- return VALUE[BOOLEAN['1']]
- return VALUE[BOOLEAN['0']]
- elif isinstance(something, int):
- return VALUE[INT[something]]
- elif isinstance(something, float):
- return VALUE[DOUBLE[something]]
-
-def generate(*args):
- params = PARAMS()
- for arg in args:
- params[PARAM[_generate(arg)]]
- return METHODRESPONSE[params]
-
-
-if __name__ == '__main__':
- print parse(""" examples.getStateName 41
-""")
-
-
-
-
-
-
-
-
-
diff --git a/indra/lib/python/indra/util/fastest_elementtree.py b/indra/lib/python/indra/util/fastest_elementtree.py
deleted file mode 100644
index 3e2189c4e7..0000000000
--- a/indra/lib/python/indra/util/fastest_elementtree.py
+++ /dev/null
@@ -1,65 +0,0 @@
-"""\
-@file fastest_elementtree.py
-@brief Concealing some gnarly import logic in here. This should export the interface of elementtree.
-
-$LicenseInfo:firstyear=2008&license=mit$
-
-Copyright (c) 2008-2009, Linden Research, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-$/LicenseInfo$
-"""
-
-# The parsing exception raised by the underlying library depends
-# on the ElementTree implementation we're using, so we provide an
-# alias here.
-#
-# Use ElementTreeError as the exception type for catching parsing
-# errors.
-
-
-# Using cElementTree might cause some unforeseen problems, so here's a
-# convenient off switch.
-
-use_celementree = True
-
-try:
- if not use_celementree:
- raise ImportError()
- # Python 2.3 and 2.4.
- from cElementTree import *
- ElementTreeError = SyntaxError
-except ImportError:
- try:
- if not use_celementree:
- raise ImportError()
- # Python 2.5 and above.
- from xml.etree.cElementTree import *
- ElementTreeError = SyntaxError
- except ImportError:
- # Pure Python code.
- try:
- # Python 2.3 and 2.4.
- from elementtree.ElementTree import *
- except ImportError:
- # Python 2.5 and above.
- from xml.etree.ElementTree import *
-
- # The pure Python ElementTree module uses Expat for parsing.
- from xml.parsers.expat import ExpatError as ElementTreeError
diff --git a/indra/lib/python/indra/util/helpformatter.py b/indra/lib/python/indra/util/helpformatter.py
deleted file mode 100644
index ba5c9b67d1..0000000000
--- a/indra/lib/python/indra/util/helpformatter.py
+++ /dev/null
@@ -1,52 +0,0 @@
-"""\
-@file helpformatter.py
-@author Phoenix
-@brief Class for formatting optparse descriptions.
-
-$LicenseInfo:firstyear=2007&license=mit$
-
-Copyright (c) 2007-2009, Linden Research, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-$/LicenseInfo$
-"""
-
-import optparse
-import textwrap
-
-class Formatter(optparse.IndentedHelpFormatter):
- def __init__(
- self,
- p_indentIncrement = 2,
- p_maxHelpPosition = 24,
- p_width = 79,
- p_shortFirst = 1) :
- optparse.HelpFormatter.__init__(
- self,
- p_indentIncrement,
- p_maxHelpPosition,
- p_width,
- p_shortFirst)
- def format_description(self, p_description):
- t_descWidth = self.width - self.current_indent
- t_indent = " " * (self.current_indent + 2)
- return "\n".join(
- [textwrap.fill(descr, t_descWidth, initial_indent = t_indent,
- subsequent_indent = t_indent)
- for descr in p_description.split("\n")] )
diff --git a/indra/lib/python/indra/util/iterators.py b/indra/lib/python/indra/util/iterators.py
deleted file mode 100644
index 9013fa6303..0000000000
--- a/indra/lib/python/indra/util/iterators.py
+++ /dev/null
@@ -1,63 +0,0 @@
-"""\
-@file iterators.py
-@brief Useful general-purpose iterators.
-
-$LicenseInfo:firstyear=2008&license=mit$
-
-Copyright (c) 2008-2009, Linden Research, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-$/LicenseInfo$
-"""
-
-from __future__ import nested_scopes
-
-def iter_chunks(rows, aggregate_size=100):
- """
- Given an iterable set of items (@p rows), produces lists of up to @p
- aggregate_size items at a time, for example:
-
- iter_chunks([1,2,3,4,5,6,7,8,9,10], 3)
-
- Values for @p aggregate_size < 1 will raise ValueError.
-
- Will return a generator that produces, in the following order:
- - [1, 2, 3]
- - [4, 5, 6]
- - [7, 8, 9]
- - [10]
- """
- if aggregate_size < 1:
- raise ValueError()
-
- def iter_chunks_inner():
- row_iter = iter(rows)
- done = False
- agg = []
- while not done:
- try:
- row = row_iter.next()
- agg.append(row)
- except StopIteration:
- done = True
- if agg and (len(agg) >= aggregate_size or done):
- yield agg
- agg = []
-
- return iter_chunks_inner()
diff --git a/indra/lib/python/indra/util/iterators_test.py b/indra/lib/python/indra/util/iterators_test.py
deleted file mode 100755
index 66928c8e7d..0000000000
--- a/indra/lib/python/indra/util/iterators_test.py
+++ /dev/null
@@ -1,72 +0,0 @@
-"""\
-@file iterators_test.py
-@brief Test cases for iterators module.
-
-$LicenseInfo:firstyear=2008&license=mit$
-
-Copyright (c) 2008-2009, Linden Research, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-$/LicenseInfo$
-"""
-
-import unittest
-
-from indra.util.iterators import iter_chunks
-
-class TestIterChunks(unittest.TestCase):
- """Unittests for iter_chunks"""
- def test_bad_agg_size(self):
- rows = [1,2,3,4]
- self.assertRaises(ValueError, iter_chunks, rows, 0)
- self.assertRaises(ValueError, iter_chunks, rows, -1)
-
- try:
- for i in iter_chunks(rows, 0):
- pass
- except ValueError:
- pass
- else:
- self.fail()
-
- try:
- result = list(iter_chunks(rows, 0))
- except ValueError:
- pass
- else:
- self.fail()
- def test_empty(self):
- rows = []
- result = list(iter_chunks(rows))
- self.assertEqual(result, [])
- def test_small(self):
- rows = [[1]]
- result = list(iter_chunks(rows, 2))
- self.assertEqual(result, [[[1]]])
- def test_size(self):
- rows = [[1],[2]]
- result = list(iter_chunks(rows, 2))
- self.assertEqual(result, [[[1],[2]]])
- def test_multi_agg(self):
- rows = [[1],[2],[3],[4],[5]]
- result = list(iter_chunks(rows, 2))
- self.assertEqual(result, [[[1],[2]],[[3],[4]],[[5]]])
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/indra/lib/python/indra/util/llmanifest.py b/indra/lib/python/indra/util/llmanifest.py
index 0059faa2ee..b285b46c7d 100644
--- a/indra/lib/python/indra/util/llmanifest.py
+++ b/indra/lib/python/indra/util/llmanifest.py
@@ -33,13 +33,26 @@
import fnmatch
import getopt
import glob
+import itertools
+import operator
import os
import re
import shutil
+import subprocess
import sys
import tarfile
-import errno
-import subprocess
+
+class ManifestError(RuntimeError):
+ """Use an exception more specific than generic Python RuntimeError"""
+ def __init__(self, msg):
+ self.msg = msg
+ super(ManifestError, self).__init__(self.msg)
+
+class MissingError(ManifestError):
+ """You specified a file that doesn't exist"""
+ def __init__(self, msg):
+ self.msg = msg
+ super(MissingError, self).__init__(self.msg)
def path_ancestors(path):
drive, path = os.path.splitdrive(os.path.normpath(path))
@@ -76,33 +89,11 @@ def get_default_platform(dummy):
'darwin':'darwin'
}[sys.platform]
-def get_default_version(srctree):
- # look up llversion.h and parse out the version info
- paths = [os.path.join(srctree, x, 'llversionviewer.h') for x in ['llcommon', '../llcommon', '../../indra/llcommon.h']]
- for p in paths:
- if os.path.exists(p):
- contents = open(p, 'r').read()
- major = re.search("LL_VERSION_MAJOR\s=\s([0-9]+)", contents).group(1)
- minor = re.search("LL_VERSION_MINOR\s=\s([0-9]+)", contents).group(1)
- patch = re.search("LL_VERSION_PATCH\s=\s([0-9]+)", contents).group(1)
- build = re.search("LL_VERSION_BUILD\s=\s([0-9]+)", contents).group(1)
- return major, minor, patch, build
-
-def get_channel(srctree):
- # look up llversionserver.h and parse out the version info
- paths = [os.path.join(srctree, x, 'llversionviewer.h') for x in ['llcommon', '../llcommon', '../../indra/llcommon.h']]
- for p in paths:
- if os.path.exists(p):
- contents = open(p, 'r').read()
- channel = re.search("LL_CHANNEL\s=\s\"(.+)\";\s*$", contents, flags = re.M).group(1)
- return channel
-
-
DEFAULT_SRCTREE = os.path.dirname(sys.argv[0])
-DEFAULT_CHANNEL = 'Second Life Release'
-DEFAULT_CHANNEL_SNOWGLOBE = 'Snowglobe Release'
+CHANNEL_VENDOR_BASE = 'Singularity'
+RELEASE_CHANNEL = CHANNEL_VENDOR_BASE + ' Release'
-ARGUMENTS=[
+BASE_ARGUMENTS=[
dict(name='actions',
description="""This argument specifies the actions that are to be taken when the
script is run. The meaningful actions are currently:
@@ -120,28 +111,23 @@ def get_channel(srctree):
Example use: %(name)s --arch=i686
On Linux this would try to use Linux_i686Manifest.""",
default=""),
+ dict(name='artwork', description='Artwork directory.', default=DEFAULT_SRCTREE),
+ dict(name='branding_id', description="Identifier for the branding set to use.", default='singularity'),
dict(name='build', description='Build directory.', default=DEFAULT_SRCTREE),
- dict(name='buildtype', description="""The build type used. ('Debug', 'Release', or 'RelWithDebInfo')
- Default is Release """,
- default="Release"),
- dict(name='branding_id', description="""Identifier for the branding set to
- use. Currently, 'secondlife' or 'snowglobe')""",
- default='secondlife'),
+ dict(name='buildtype', description='Build type (i.e. Debug, Release, RelWithDebInfo).', default=None),
+ dict(name='channel',
+ description="""The channel to use for updates, packaging, settings name, etc.""",
+ default='CHANNEL UNSET'),
+ dict(name='channel_suffix',
+ description="""Addition to the channel for packaging and channel value,
+ but not application name (used internally)""",
+ default=None),
dict(name='configuration',
- description="""The build configuration used. Only used on OS X for
- now, but it could be used for other platforms as well.""",
- default="Universal"),
+ description="""The build configuration used.""",
+ default="Release"),
dict(name='dest', description='Destination directory.', default=DEFAULT_SRCTREE),
dict(name='grid',
- description="""Which grid the client will try to connect to. Even
- though it's not strictly a grid, 'firstlook' is also an acceptable
- value for this parameter.""",
- default=""),
- dict(name='channel',
- description="""The channel to use for updates, packaging, settings name, etc.""",
- default=get_channel),
- dict(name='login_channel',
- description="""The channel to use for login handshake/updates only.""",
+ description="""Which grid the client will try to connect to.""",
default=None),
dict(name='installer_name',
description=""" The name of the file that the installer should be
@@ -154,34 +140,33 @@ def get_channel(srctree):
description="""The current platform, to be used for looking up which
manifest class to run.""",
default=get_default_platform),
+ dict(name='signature',
+ description="""This specifies an identity to sign the viewer with, if any.
+ If no value is supplied, the default signature will be used, if any. Currently
+ only used on Mac OS X.""",
+ default=None),
dict(name='source',
description='Source directory.',
default=DEFAULT_SRCTREE),
dict(name='standalone',
description='Set to ON if this is a standalone build.',
default="OFF"),
- dict(name='artwork', description='Artwork directory.', default=DEFAULT_SRCTREE),
dict(name='touch',
description="""File to touch when action is finished. Touch file will
contain the name of the final package in a form suitable
for use by a .bat file.""",
default=None),
- dict(name='version',
- description="""This specifies the version of Second Life that is
- being packaged up.""",
- default=get_default_version),
- dict(name='extra_libraries',
- description="""List of extra libraries to include in package""",
- default=None)
+ dict(name='versionfile',
+ description="""The name of a file containing the full version number."""),
]
-def usage(srctree=""):
+def usage(arguments, srctree=""):
nd = {'name':sys.argv[0]}
print """Usage:
%(name)s [options] [destdir]
Options:
""" % nd
- for arg in ARGUMENTS:
+ for arg in arguments:
default = arg['default']
if hasattr(default, '__call__'):
default = "(computed value) \"" + str(default(srctree)) + '"'
@@ -192,10 +177,15 @@ def usage(srctree=""):
default,
arg['description'] % nd)
-def main():
- print "cwd:", os.getcwd()
- print " ".join(sys.argv)
- option_names = [arg['name'] + '=' for arg in ARGUMENTS]
+def main(extra=[]):
+## print ' '.join((("'%s'" % item) if ' ' in item else item)
+## for item in itertools.chain([sys.executable], sys.argv))
+ # Supplement our default command-line switches with any desired by
+ # application-specific caller.
+ arguments = list(itertools.chain(BASE_ARGUMENTS, extra))
+ # Alphabetize them by option name in case we display usage.
+ arguments.sort(key=operator.itemgetter('name'))
+ option_names = [arg['name'] + '=' for arg in arguments]
option_names.append('help')
options, remainder = getopt.getopt(sys.argv[1:], "", option_names)
@@ -218,11 +208,11 @@ def main():
# early out for help
if 'help' in args:
# *TODO: it is a huge hack to pass around the srctree like this
- usage(args['source'])
+ usage(arguments, srctree=args['source'])
return
# defaults
- for arg in ARGUMENTS:
+ for arg in arguments:
if arg['name'] not in args:
default = arg['default']
if hasattr(default, '__call__'):
@@ -231,12 +221,17 @@ def main():
args[arg['name']] = default
# fix up version
- if isinstance(args.get('version'), str):
- args['version'] = args['version'].split('.')
-
- # default and agni are default
- if args['grid'] in ['default', 'agni']:
- args['grid'] = ''
+ if isinstance(args.get('versionfile'), str):
+ try: # read in the version string
+ vf = open(args['versionfile'], 'r')
+ args['version'] = vf.read().strip().split('.')
+ except:
+ print "Unable to read versionfile '%s'" % args['versionfile']
+ raise
+
+ # unspecified, default, and agni are default
+ if args['grid'] in ['', 'default', 'agni']:
+ args['grid'] = None
if 'actions' in args:
args['actions'] = args['actions'].split()
@@ -245,16 +240,69 @@ def main():
for opt in args:
print "Option:", opt, "=", args[opt]
+ # pass in sourceid as an argument now instead of an environment variable
+ args['sourceid'] = os.environ.get("sourceid", "")
+
+ # Build base package.
+ touch = args.get('touch')
+ if touch:
+ print '================ Creating base package'
+ else:
+ print '================ Starting base copy'
wm = LLManifest.for_platform(args['platform'], args.get('arch'))(args)
wm.do(*args['actions'])
-
+ # Store package file for later if making touched file.
+ base_package_file = ""
+ if touch:
+ print '================ Created base package ', wm.package_file
+ base_package_file = "" + wm.package_file
+ else:
+ print '================ Finished base copy'
+
+ # handle multiple packages if set
+ # ''.split() produces empty list
+ additional_packages = os.environ.get("additional_packages", "").split()
+ if additional_packages:
+ # Determine destination prefix / suffix for additional packages.
+ base_dest_parts = list(os.path.split(args['dest']))
+ base_dest_parts.insert(-1, "{}")
+ base_dest_template = os.path.join(*base_dest_parts)
+ # Determine touched prefix / suffix for additional packages.
+ if touch:
+ base_touch_parts = list(os.path.split(touch))
+ # Because of the special insert() logic below, we don't just want
+ # [dirpath, basename]; we want [dirpath, directory, basename].
+ # Further split the dirpath and replace it in the list.
+ base_touch_parts[0:1] = os.path.split(base_touch_parts[0])
+ if "arwin" in args['platform']:
+ base_touch_parts.insert(-1, "{}")
+ else:
+ base_touch_parts.insert(-2, "{}")
+ base_touch_template = os.path.join(*base_touch_parts)
+ for package_id in additional_packages:
+ args['channel_suffix'] = os.environ.get(package_id + "_viewer_channel_suffix")
+ args['sourceid'] = os.environ.get(package_id + "_sourceid")
+ args['dest'] = base_dest_template.format(package_id)
+ if touch:
+ print '================ Creating additional package for "', package_id, '" in ', args['dest']
+ else:
+ print '================ Starting additional copy for "', package_id, '" in ', args['dest']
+ try:
+ wm = LLManifest.for_platform(args['platform'], args.get('arch'))(args)
+ wm.do(*args['actions'])
+ except Exception as err:
+ sys.exit(str(err))
+ if touch:
+ print '================ Created additional package ', wm.package_file, ' for ', package_id
+ with open(base_touch_template.format(package_id), 'w') as fp:
+ fp.write('set package_file=%s\n' % wm.package_file)
+ else:
+ print '================ Finished additional copy "', package_id, '" in ', args['dest']
# Write out the package file in this format, so that it can easily be called
# and used in a .bat file - yeah, it sucks, but this is the simplest...
- touch = args.get('touch')
if touch:
- fp = open(touch, 'w')
- fp.write('set package_file=%s\n' % wm.package_file)
- fp.close()
+ with open(touch, 'w') as fp:
+ fp.write('set package_file=%s\n' % base_package_file)
print 'touched', touch
return 0
@@ -269,8 +317,8 @@ class LLManifest(object):
__metaclass__ = LLManifestRegistry
manifests = {}
def for_platform(self, platform, arch = None):
- if arch and platform != "windows":
- platform = platform + '_' + arch
+ if arch:
+ platform = platform + '_' + arch + '_'
return self.manifests[platform.lower()]
for_platform = classmethod(for_platform)
@@ -280,26 +328,15 @@ def __init__(self, args):
self.file_list = []
self.excludes = []
self.actions = []
- self.src_prefix = list([args['source']])
- self.artwork_prefix = list([args['artwork']])
- self.build_prefix = list([args['build']])
- self.alt_build_prefix = list([args['build']])
- self.dst_prefix = list([args['dest']])
+ self.src_prefix = [args['source']]
+ self.artwork_prefix = [args['artwork']]
+ self.build_prefix = [args['build']]
+ self.dst_prefix = [args['dest']]
self.created_paths = []
self.package_name = "Unknown"
-
- def default_grid(self):
- return self.args.get('grid', None) == ''
+
def default_channel(self):
- return self.args.get('channel', None) == DEFAULT_CHANNEL
-
- def default_channel_for_brand(self):
- if self.viewer_branding_id()=='secondlife':
- return self.args.get('channel', None) == DEFAULT_CHANNEL
- elif self.viewer_branding_id()=="snowglobe":
- return self.args.get('channel', None) == DEFAULT_CHANNEL_SNOWGLOBE
- else:
- return True
+ return self.args.get('channel', None) == RELEASE_CHANNEL
def construct(self):
""" Meant to be overriden by LLManifest implementors with code that
@@ -311,27 +348,113 @@ def exclude(self, glob):
in the file list by path()."""
self.excludes.append(glob)
- def prefix(self, src='', build=None, dst=None, alt_build=None):
- """ Pushes a prefix onto the stack. Until end_prefix is
- called, all relevant method calls (esp. to path()) will prefix
- paths with the entire prefix stack. Source and destination
- prefixes can be different, though if only one is provided they
- are both equal. To specify a no-op, use an empty string, not
- None."""
- if dst is None:
- dst = src
- if build is None:
- build = src
- if alt_build is None:
- alt_build = build
+ def prefix(self, src='', build='', dst='', src_dst=None):
+ """
+ Usage:
+
+ with self.prefix(...args as described...):
+ self.path(...)
+
+ For the duration of the 'with' block, pushes a prefix onto the stack.
+ Within that block, all relevant method calls (esp. to path()) will
+ prefix paths with the entire prefix stack. Source and destination
+ prefixes are independent; if omitted (or passed as the empty string),
+ the prefix has no effect. Thus:
+
+ with self.prefix(src='foo'):
+ # no effect on dst
+
+ with self.prefix(dst='bar'):
+ # no effect on src
+ If you want to set both at once, use src_dst:
+
+ with self.prefix(src_dst='subdir'):
+ # same as self.prefix(src='subdir', dst='subdir')
+ # Passing src_dst makes any src or dst argument in the same
+ # parameter list irrelevant.
+
+ Also supports the older (pre-Python-2.5) syntax:
+
+ if self.prefix(...args as described...):
+ self.path(...)
+ self.end_prefix(...)
+
+ Before the arrival of the 'with' statement, one was required to code
+ self.prefix() and self.end_prefix() in matching pairs to push and to
+ pop the prefix stacks, respectively. The older prefix() method
+ returned True specifically so that the caller could indent the
+ relevant block of code with 'if', just for aesthetic purposes.
+ """
+ if src_dst is not None:
+ src = src_dst
+ dst = src_dst
self.src_prefix.append(src)
self.artwork_prefix.append(src)
self.build_prefix.append(build)
self.dst_prefix.append(dst)
- self.alt_build_prefix.append(alt_build)
- return True # so that you can wrap it in an if to get indentation
+## self.display_stacks()
+
+ # The above code is unchanged from the original implementation. What's
+ # new is the return value. We're going to return an instance of
+ # PrefixManager that binds this LLManifest instance and Does The Right
+ # Thing on exit.
+ return self.PrefixManager(self)
+
+ def display_stacks(self):
+ width = 1 + max(len(stack) for stack in self.PrefixManager.stacks)
+ for stack in self.PrefixManager.stacks:
+ print "{} {}".format((stack + ':').ljust(width),
+ os.path.join(*getattr(self, stack)))
+
+ class PrefixManager(object):
+ # stack attributes we manage in this LLManifest (sub)class
+ # instance
+ stacks = ("src_prefix", "artwork_prefix", "build_prefix", "dst_prefix")
+
+ def __init__(self, manifest):
+ self.manifest = manifest
+ # If the caller wrote:
+ # with self.prefix(...):
+ # as intended, then bind the state of each prefix stack as it was
+ # just BEFORE the call to prefix(). Since prefix() appended an
+ # entry to each prefix stack, capture len()-1.
+ self.prevlen = { stack: len(getattr(self.manifest, stack)) - 1
+ for stack in self.stacks }
+
+ def __nonzero__(self):
+ # If the caller wrote:
+ # if self.prefix(...):
+ # then a value of this class had better evaluate as 'True'.
+ return True
+
+ def __enter__(self):
+ # nobody uses 'with self.prefix(...) as variable:'
+ return None
+
+ def __exit__(self, type, value, traceback):
+ # First, if the 'with' block raised an exception, just propagate.
+ # Do NOT swallow it.
+ if type is not None:
+ return False
+
+ # Okay, 'with' block completed successfully. Restore previous
+ # state of each of the prefix stacks in self.stacks.
+ # Note that we do NOT simply call pop() on them as end_prefix()
+ # does. This is to cope with the possibility that the coder
+ # changed 'if self.prefix(...):' to 'with self.prefix(...):' yet
+ # forgot to remove the self.end_prefix(...) call at the bottom of
+ # the block. In that case, calling pop() again would be Bad! But
+ # if we restore the length of each stack to what it was before the
+ # current prefix() block, it doesn't matter whether end_prefix()
+ # was called or not.
+ for stack, prevlen in self.prevlen.items():
+ # find the attribute in 'self.manifest' named by 'stack', and
+ # truncate that list back to 'prevlen'
+ del getattr(self.manifest, stack)[prevlen:]
+
+## self.manifest.display_stacks()
def end_prefix(self, descr=None):
"""Pops a prefix off the stack. If given an argument, checks
@@ -343,30 +466,25 @@ def end_prefix(self, descr=None):
src = self.src_prefix.pop()
artwork = self.artwork_prefix.pop()
build = self.build_prefix.pop()
- alt_build_prefix = self.alt_build_prefix.pop()
dst = self.dst_prefix.pop()
if descr and not(src == descr or build == descr or dst == descr):
raise ValueError, "End prefix '" + descr + "' didn't match '" +src+ "' or '" +dst + "'"
def get_src_prefix(self):
""" Returns the current source prefix."""
- return os.path.relpath(os.path.normpath(os.path.join(*self.src_prefix)))
+ return os.path.join(*self.src_prefix)
def get_artwork_prefix(self):
""" Returns the current artwork prefix."""
- return os.path.relpath(os.path.normpath(os.path.join(*self.artwork_prefix)))
+ return os.path.join(*self.artwork_prefix)
def get_build_prefix(self):
""" Returns the current build prefix."""
- return os.path.relpath(os.path.normpath(os.path.join(*self.build_prefix)))
-
- def get_alt_build_prefix(self):
- """ Returns the current alternate source prefix."""
- return os.path.relpath(os.path.normpath(os.path.join(*self.alt_build_prefix)))
+ return os.path.join(*self.build_prefix)
def get_dst_prefix(self):
""" Returns the current destination prefix."""
- return os.path.relpath(os.path.normpath(os.path.join(*self.dst_prefix)))
+ return os.path.join(*self.dst_prefix)
def src_path_of(self, relpath):
"""Returns the full path to a file or directory specified
@@ -383,40 +501,72 @@ def dst_path_of(self, relpath):
relative to the destination directory."""
return os.path.join(self.get_dst_prefix(), relpath)
+ def _relative_dst_path(self, dstpath):
+ """
+ Returns the path to a file or directory relative to the destination directory.
+ This should only be used for generating diagnostic output in the path method.
+ """
+ dest_root=self.dst_prefix[0]
+ if dstpath.startswith(dest_root+os.path.sep):
+ return dstpath[len(dest_root)+1:]
+ elif dstpath.startswith(dest_root):
+ return dstpath[len(dest_root):]
+ else:
+ return dstpath
+
+ def ensure_src_dir(self, reldir):
+ """Construct the path for a directory relative to the
+ source path, and ensures that it exists. Returns the
+ full path."""
+ path = os.path.join(self.get_src_prefix(), reldir)
+ self.cmakedirs(path)
+ return path
+
+ def ensure_dst_dir(self, reldir):
+ """Construct the path for a directory relative to the
+ destination path, and ensures that it exists. Returns the
+ full path."""
+ path = os.path.join(self.get_dst_prefix(), reldir)
+ self.cmakedirs(path)
+ return path
+
def run_command(self, command):
- """ Runs an external command, and returns the output. Raises
- an exception if the command reurns a nonzero status code. For
- debugging/informational purpoases, prints out the command's
- output as it is received."""
+ """
+ Runs an external command.
+ Raises ManifestError exception if the command returns a nonzero status.
+ """
print "Running command:", command
- fd = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
- lines = []
- while True:
- lines.append(fd.stdout.readline())
- if lines[-1] == '':
- break
- else:
- print lines[-1].rstrip('\n'),
- output = ''.join(lines)
- if fd.returncode:
- raise RuntimeError(
- "Command %s returned non-zero status (%s) \noutput:\n%s"
- % (command, fd.returncode, output) )
- return output
+ sys.stdout.flush()
+ try:
+ subprocess.check_call(command)
+ except subprocess.CalledProcessError as err:
+ raise ManifestError( "Command %s returned non-zero status (%s)"
+ % (command, err.returncode) )
def created_path(self, path):
""" Declare that you've created a path in order to
a) verify that you really have created it
b) schedule it for cleanup"""
if not os.path.exists(path):
- raise RuntimeError, "Should be something at path " + path
+ raise ManifestError, "Should be something at path " + path
self.created_paths.append(path)
- def put_in_file(self, contents, dst):
+ def put_in_file(self, contents, dst, src=None):
# write contents as dst
- f = open(self.dst_path_of(dst), "wb")
- f.write(contents)
- f.close()
+ dst_path = self.dst_path_of(dst)
+ self.cmakedirs(os.path.dirname(dst_path))
+ f = open(dst_path, "wb")
+ try:
+ f.write(contents)
+ finally:
+ f.close()
+
+ # Why would we create a file in the destination tree if not to include
+ # it in the installer? The default src=None (plus the fact that the
+ # src param is last) is to preserve backwards compatibility.
+ if src:
+ self.file_list.append([src, dst_path])
+ return dst_path
def replace_in(self, src, dst=None, searchdict={}):
if dst == None:
@@ -436,11 +586,7 @@ def copy_action(self, src, dst):
# ensure that destination path exists
self.cmakedirs(os.path.dirname(dst))
self.created_paths.append(dst)
- if not os.path.isdir(src):
- self.ccopy(src,dst)
- else:
- # src is a dir
- self.ccopytree(src,dst)
+ self.ccopymumble(src, dst)
else:
print "Doesn't exist:", src
@@ -470,39 +616,42 @@ def cleanup_finish(self):
# *TODO is this gonna be useful?
print "Cleaning up " + c
+ def process_either(self, src, dst):
+ # If it's a real directory, recurse through it --
+ # but not a symlink! Handle those like files.
+ if os.path.isdir(src) and not os.path.islink(src):
+ return self.process_directory(src, dst)
+ else:
+ return self.process_file(src, dst)
+
def process_file(self, src, dst):
if self.includes(src, dst):
-# print src, "=>", dst
for action in self.actions:
methodname = action + "_action"
method = getattr(self, methodname, None)
if method is not None:
method(src, dst)
self.file_list.append([src, dst])
- return [dst]
+ return 1
else:
sys.stdout.write(" (excluding %r, %r)" % (src, dst))
sys.stdout.flush()
- return []
+ return 0
def process_directory(self, src, dst):
if not self.includes(src, dst):
sys.stdout.write(" (excluding %r, %r)" % (src, dst))
sys.stdout.flush()
- return []
+ return 0
names = os.listdir(src)
self.cmakedirs(dst)
errors = []
- found_files = []
count = 0
for name in names:
srcname = os.path.join(src, name)
dstname = os.path.join(dst, name)
- if os.path.isdir(srcname):
- found_files.extend(self.process_directory(srcname, dstname))
- else:
- found_files.extend(self.process_file(srcname, dstname))
- return found_files
+ count += self.process_either(srcname, dstname)
+ return count
def includes(self, src, dst):
if src:
@@ -520,28 +669,43 @@ def remove(self, *paths):
else:
os.remove(path)
- def ccopy(self, src, dst):
- """ Copy a single file or symlink. Uses filecmp to skip copying for existing files."""
+ def ccopymumble(self, src, dst):
+ """Copy a single symlink, file or directory."""
if os.path.islink(src):
linkto = os.readlink(src)
- if os.path.islink(dst) or os.path.exists(dst):
+ if os.path.islink(dst) or os.path.isfile(dst):
os.remove(dst) # because symlinking over an existing link fails
+ elif os.path.isdir(dst):
+ shutil.rmtree(dst)
os.symlink(linkto, dst)
+ elif os.path.isdir(src):
+ self.ccopytree(src, dst)
else:
- # Don't recopy file if it's up-to-date.
- # If we seem to be not not overwriting files that have been
- # updated, set the last arg to False, but it will take longer.
- if os.path.exists(dst) and filecmp.cmp(src, dst, True):
- return
- # only copy if it's not excluded
- if self.includes(src, dst):
- try:
- os.unlink(dst)
- except OSError, err:
- if err.errno != errno.ENOENT:
- raise
-
- shutil.copy2(src, dst)
+ self.ccopyfile(src, dst)
+ # XXX What about devices, sockets etc.?
+ # YYY would we put such things into a viewer package?!
+
+ def ccopyfile(self, src, dst):
+ """ Copy a single file. Uses filecmp to skip copying for existing files."""
+ # Don't recopy file if it's up-to-date.
+ # If we seem to be not not overwriting files that have been
+ # updated, set the last arg to False, but it will take longer.
+## reldst = (dst[len(self.dst_prefix[0]):]
+## if dst.startswith(self.dst_prefix[0])
+## else dst).lstrip(r'\/')
+ if os.path.exists(dst) and filecmp.cmp(src, dst, True):
+## print "{} (skipping, {} exists)".format(src, reldst)
+ return
+ # only copy if it's not excluded
+ if self.includes(src, dst):
+ try:
+ os.unlink(dst)
+ except OSError as err:
+ if err.errno != errno.ENOENT:
+ raise
+
+## print "{} => {}".format(src, reldst)
+ shutil.copy2(src, dst)
def ccopytree(self, src, dst):
"""Direct copy of shutil.copytree with the additional
@@ -557,15 +721,11 @@ def ccopytree(self, src, dst):
srcname = os.path.join(src, name)
dstname = os.path.join(dst, name)
try:
- if os.path.isdir(srcname):
- self.ccopytree(srcname, dstname)
- else:
- self.ccopy(srcname, dstname)
- # XXX What about devices, sockets etc.?
- except (IOError, os.error), why:
+ self.ccopymumble(srcname, dstname)
+ except (IOError, os.error) as why:
errors.append((srcname, dstname, why))
if errors:
- raise RuntimeError, errors
+ raise ManifestError, errors
def cmakedirs(self, path):
@@ -582,11 +742,25 @@ def find_existing_file(self, *list):
if os.path.exists(f):
return f
# didn't find it, return last item in list
- if list:
+ if len(list) > 0:
return list[-1]
else:
return None
+ def contents_of_tar(self, src_tar, dst_dir):
+ """ Extracts the contents of the tarfile (specified
+ relative to the source prefix) into the directory
+ specified relative to the destination directory."""
+ self.check_file_exists(src_tar)
+ tf = tarfile.open(self.src_path_of(src_tar), 'r')
+ for member in tf.getmembers():
+ tf.extract(member, self.ensure_dst_dir(dst_dir))
+ # TODO get actions working on these dudes, perhaps we should extract to a temporary directory and then process_directory on it?
+ self.file_list.append([src_tar,
+ self.dst_path_of(os.path.join(dst_dir,member.name))])
+ tf.close()
+
+
def wildcard_regex(self, src_glob, dst_glob):
src_re = re.escape(src_glob)
src_re = src_re.replace('\*', '([-a-zA-Z0-9._ ]*)')
@@ -597,7 +771,12 @@ def wildcard_regex(self, src_glob, dst_glob):
i = i+1
return re.compile(src_re), dst_temp
- wildcard_pattern = re.compile('\*')
+ def check_file_exists(self, path):
+ if not os.path.exists(path) and not os.path.islink(path):
+ raise MissingError("Path %s doesn't exist" % (os.path.abspath(path),))
+
+
+ wildcard_pattern = re.compile(r'\*')
def expand_globs(self, src, dst):
src_list = glob.glob(src)
src_re, d_template = self.wildcard_regex(src.replace('\\', '/'),
@@ -626,41 +805,43 @@ def path2basename(self, path, file):
def path(self, src, dst=None):
sys.stdout.flush()
if src == None:
- raise RuntimeError("No source file, dst is " + dst)
+ raise ManifestError("No source file, dst is " + dst)
if dst == None:
dst = src
dst = os.path.join(self.get_dst_prefix(), dst)
- sys.stdout.write("Processing %s => %s ... " % (src, dst))
- count = 0
- is_glob = False
- found_files = []
-
- # look under each prefix for matching paths. Paths are normalized so './../blah' will match '../blah/../blah/'
- paths = set([os.path.normpath(os.path.join(self.get_src_prefix(), src)),
- os.path.normpath(os.path.join(self.get_artwork_prefix(), src)),
- os.path.normpath(os.path.join(self.get_build_prefix(), src)),
- os.path.normpath(os.path.join(self.get_alt_build_prefix(), src))]
- )
- for path in paths:
- if self.wildcard_pattern.search(path):
- is_glob = True
- for s,d in self.expand_globs(path, dst):
+ sys.stdout.write("Processing %s => %s ... " % (src, self._relative_dst_path(dst)))
+
+ def try_path(src):
+ # expand globs
+ count = 0
+ if self.wildcard_pattern.search(src):
+ for s,d in self.expand_globs(src, dst):
assert(s != d)
- found_files.extend(self.process_file(s, d))
+ count += self.process_file(s, d)
else:
- # if it's a directory, recurse through it
- if os.path.isdir(path):
- found_files.extend(self.process_directory(path, dst))
- elif os.path.exists(path):
- found_files.extend(self.process_file(path, dst))
-
- # if we're specifying a single path (not a glob),
- # we should error out if it doesn't exist
- if not found_files and not is_glob:
- raise RuntimeError("No files match %s\n" % str(paths))
-
- print "%d files" % len(found_files)
- return found_files
+ # if we're specifying a single path (not a glob),
+ # we should error out if it doesn't exist
+ self.check_file_exists(src)
+ count += self.process_either(src, dst)
+ return count
+
+ try_prefixes = [self.get_src_prefix(), self.get_artwork_prefix(), self.get_build_prefix()]
+ tried=[]
+ count=0
+ while not count and try_prefixes:
+ pfx = try_prefixes.pop(0)
+ try:
+ count = try_path(os.path.join(pfx, src))
+ except MissingError:
+ tried.append(pfx)
+ if not try_prefixes:
+ # no more prefixes left to try
+ print "unable to find '%s'; looked in:\n %s" % (src, '\n '.join(tried))
+ print "%d files" % count
+
+ # Let caller check whether we processed as many files as expected. In
+ # particular, let caller notice 0.
+ return count
def do(self, *actions):
self.actions = actions
diff --git a/indra/lib/python/indra/util/llperformance.py b/indra/lib/python/indra/util/llperformance.py
deleted file mode 100755
index 57dd64de3f..0000000000
--- a/indra/lib/python/indra/util/llperformance.py
+++ /dev/null
@@ -1,182 +0,0 @@
-#!/usr/bin/env python
-"""\
-@file llperformance.py
-
-$LicenseInfo:firstyear=2010&license=viewerlgpl$
-Second Life Viewer Source Code
-Copyright (C) 2010-2011, 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$
-"""
-
-# ------------------------------------------------
-# Sim metrics utility functions.
-
-import glob, os, time, sys, stat, exceptions
-
-from indra.base import llsd
-
-gBlockMap = {} #Map of performance metric data with function hierarchy information.
-gCurrentStatPath = ""
-
-gIsLoggingEnabled=False
-
-class LLPerfStat:
- def __init__(self,key):
- self.mTotalTime = 0
- self.mNumRuns = 0
- self.mName=key
- self.mTimeStamp = int(time.time()*1000)
- self.mUTCTime = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
-
- def __str__(self):
- return "%f" % self.mTotalTime
-
- def start(self):
- self.mStartTime = int(time.time() * 1000000)
- self.mNumRuns += 1
-
- def stop(self):
- execution_time = int(time.time() * 1000000) - self.mStartTime
- self.mTotalTime += execution_time
-
- def get_map(self):
- results={}
- results['name']=self.mName
- results['utc_time']=self.mUTCTime
- results['timestamp']=self.mTimeStamp
- results['us']=self.mTotalTime
- results['count']=self.mNumRuns
- return results
-
-class PerfError(exceptions.Exception):
- def __init__(self):
- return
-
- def __Str__(self):
- print "","Unfinished LLPerfBlock"
-
-class LLPerfBlock:
- def __init__( self, key ):
- global gBlockMap
- global gCurrentStatPath
- global gIsLoggingEnabled
-
- #Check to see if we're running metrics right now.
- if gIsLoggingEnabled:
- self.mRunning = True #Mark myself as running.
-
- self.mPreviousStatPath = gCurrentStatPath
- gCurrentStatPath += "/" + key
- if gCurrentStatPath not in gBlockMap:
- gBlockMap[gCurrentStatPath] = LLPerfStat(key)
-
- self.mStat = gBlockMap[gCurrentStatPath]
- self.mStat.start()
-
- def finish( self ):
- global gBlockMap
- global gIsLoggingEnabled
-
- if gIsLoggingEnabled:
- self.mStat.stop()
- self.mRunning = False
- gCurrentStatPath = self.mPreviousStatPath
-
-# def __del__( self ):
-# if self.mRunning:
-# #SPATTERS FIXME
-# raise PerfError
-
-class LLPerformance:
- #--------------------------------------------------
- # Determine whether or not we want to log statistics
-
- def __init__( self, process_name = "python" ):
- self.process_name = process_name
- self.init_testing()
- self.mTimeStamp = int(time.time()*1000)
- self.mUTCTime = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
-
- def init_testing( self ):
- global gIsLoggingEnabled
-
- host_performance_file = "/dev/shm/simperf/simperf_proc_config.llsd"
-
- #If file exists, open
- if os.path.exists(host_performance_file):
- file = open (host_performance_file,'r')
-
- #Read serialized LLSD from file.
- body = llsd.parse(file.read())
-
- #Calculate time since file last modified.
- stats = os.stat(host_performance_file)
- now = time.time()
- mod = stats[stat.ST_MTIME]
- age = now - mod
-
- if age < ( body['duration'] ):
- gIsLoggingEnabled = True
-
-
- def get ( self ):
- global gIsLoggingEnabled
- return gIsLoggingEnabled
-
- #def output(self,ptr,path):
- # if 'stats' in ptr:
- # stats = ptr['stats']
- # self.mOutputPtr[path] = stats.get_map()
-
- # if 'children' in ptr:
- # children=ptr['children']
-
- # curptr = self.mOutputPtr
- # curchildren={}
- # curptr['children'] = curchildren
-
- # for key in children:
- # curchildren[key]={}
- # self.mOutputPtr = curchildren[key]
- # self.output(children[key],path + '/' + key)
-
- def done(self):
- global gBlockMap
-
- if not self.get():
- return
-
- output_name = "/dev/shm/simperf/%s_proc.%d.llsd" % (self.process_name, os.getpid())
- output_file = open(output_name, 'w')
- process_info = {
- "name" : self.process_name,
- "pid" : os.getpid(),
- "ppid" : os.getppid(),
- "timestamp" : self.mTimeStamp,
- "utc_time" : self.mUTCTime,
- }
- output_file.write(llsd.format_notation(process_info))
- output_file.write('\n')
-
- for key in gBlockMap.keys():
- gBlockMap[key] = gBlockMap[key].get_map()
- output_file.write(llsd.format_notation(gBlockMap))
- output_file.write('\n')
- output_file.close()
-
diff --git a/indra/lib/python/indra/util/llsubprocess.py b/indra/lib/python/indra/util/llsubprocess.py
deleted file mode 100644
index 7e0e115d14..0000000000
--- a/indra/lib/python/indra/util/llsubprocess.py
+++ /dev/null
@@ -1,117 +0,0 @@
-"""\
-@file llsubprocess.py
-@author Phoenix
-@date 2008-01-18
-@brief The simplest possible wrapper for a common sub-process paradigm.
-
-$LicenseInfo:firstyear=2007&license=mit$
-
-Copyright (c) 2007-2009, Linden Research, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-$/LicenseInfo$
-"""
-
-import os
-import popen2
-import time
-import select
-
-class Timeout(RuntimeError):
- "Exception raised when a subprocess times out."
- pass
-
-def run(command, args=None, data=None, timeout=None):
- """\
-@brief Run command with arguments
-
-This is it. This is the function I want to run all the time when doing
-subprocces, but end up copying the code everywhere. none of the
-standard commands are secure and provide a way to specify input, get
-all the output, and get the result.
-@param command A string specifying a process to launch.
-@param args Arguments to be passed to command. Must be list, tuple or None.
-@param data input to feed to the command.
-@param timeout Maximum number of many seconds to run.
-@return Returns (result, stdout, stderr) from process.
-"""
- cmd = [command]
- if args:
- cmd.extend([str(arg) for arg in args])
- #print "cmd: ","' '".join(cmd)
- child = popen2.Popen3(cmd, True)
- #print child.pid
- out = []
- err = []
- result = -1
- time_left = timeout
- tochild = [child.tochild.fileno()]
- while True:
- time_start = time.time()
- #print "time:",time_left
- p_in, p_out, p_err = select.select(
- [child.fromchild.fileno(), child.childerr.fileno()],
- tochild,
- [],
- time_left)
- if p_in:
- new_line = os.read(child.fromchild.fileno(), 32 * 1024)
- if new_line:
- #print "line:",new_line
- out.append(new_line)
- new_line = os.read(child.childerr.fileno(), 32 * 1024)
- if new_line:
- #print "error:", new_line
- err.append(new_line)
- if p_out:
- if data:
- #print "p_out"
- bytes = os.write(child.tochild.fileno(), data)
- data = data[bytes:]
- if len(data) == 0:
- data = None
- tochild = []
- child.tochild.close()
- result = child.poll()
- if result != -1:
- # At this point, the child process has exited and result
- # is the return value from the process. Between the time
- # we called select() and poll() the process may have
- # exited so read all the data left on the child process
- # stdout and stderr.
- last = child.fromchild.read()
- if last:
- out.append(last)
- last = child.childerr.read()
- if last:
- err.append(last)
- child.tochild.close()
- child.fromchild.close()
- child.childerr.close()
- break
- if time_left is not None:
- time_left -= (time.time() - time_start)
- if time_left < 0:
- raise Timeout
- #print "result:",result
- out = ''.join(out)
- #print "stdout:", out
- err = ''.join(err)
- #print "stderr:", err
- return result, out, err
diff --git a/indra/lib/python/indra/util/named_query.py b/indra/lib/python/indra/util/named_query.py
deleted file mode 100644
index 6bf956107d..0000000000
--- a/indra/lib/python/indra/util/named_query.py
+++ /dev/null
@@ -1,592 +0,0 @@
-"""\
-@file named_query.py
-@author Ryan Williams, Phoenix
-@date 2007-07-31
-@brief An API for running named queries.
-
-$LicenseInfo:firstyear=2007&license=mit$
-
-Copyright (c) 2007-2009, Linden Research, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-$/LicenseInfo$
-"""
-
-import errno
-import MySQLdb
-import MySQLdb.cursors
-import os
-import os.path
-import re
-import time
-
-from indra.base import llsd
-from indra.base import config
-
-DEBUG = False
-NQ_FILE_SUFFIX = config.get('named-query-file-suffix', '.nq')
-NQ_FILE_SUFFIX_LEN = len(NQ_FILE_SUFFIX)
-
-_g_named_manager = None
-
-def _init_g_named_manager(sql_dir = None):
- """Initializes a global NamedManager object to point at a
- specified named queries hierarchy.
-
- This function is intended entirely for testing purposes,
- because it's tricky to control the config from inside a test."""
- global NQ_FILE_SUFFIX
- NQ_FILE_SUFFIX = config.get('named-query-file-suffix', '.nq')
- global NQ_FILE_SUFFIX_LEN
- NQ_FILE_SUFFIX_LEN = len(NQ_FILE_SUFFIX)
-
- if sql_dir is None:
- sql_dir = config.get('named-query-base-dir')
-
- # extra fallback directory in case config doesn't return what we want
- if sql_dir is None:
- sql_dir = os.path.abspath(
- os.path.join(
- os.path.realpath(os.path.dirname(__file__)), "..", "..", "..", "..", "web", "dataservice", "sql"))
-
- global _g_named_manager
- _g_named_manager = NamedQueryManager(
- os.path.abspath(os.path.realpath(sql_dir)))
-
-def get(name, schema = None):
- "Get the named query object to be used to perform queries"
- if _g_named_manager is None:
- _init_g_named_manager()
- return _g_named_manager.get(name).for_schema(schema)
-
-def sql(connection, name, params):
- # use module-global NamedQuery object to perform default substitution
- return get(name).sql(connection, params)
-
-def run(connection, name, params, expect_rows = None):
- """\
-@brief given a connection, run a named query with the params
-
-Note that this function will fetch ALL rows.
-@param connection The connection to use
-@param name The name of the query to run
-@param params The parameters passed into the query
-@param expect_rows The number of rows expected. Set to 1 if return_as_map is true. Raises ExpectationFailed if the number of returned rows doesn't exactly match. Kind of a hack.
-@return Returns the result set as a list of dicts.
-"""
- return get(name).run(connection, params, expect_rows)
-
-class ExpectationFailed(Exception):
- """ Exception that is raised when an expectation for an sql query
- is not met."""
- def __init__(self, message):
- Exception.__init__(self, message)
- self.message = message
-
-class NamedQuery(object):
- def __init__(self, name, filename):
- """ Construct a NamedQuery object. The name argument is an
- arbitrary name as a handle for the query, and the filename is
- a path to a file or a file-like object containing an llsd named
- query document."""
- self._stat_interval_seconds = 5 # 5 seconds
- self._name = name
- if (filename is not None and isinstance(filename, (str, unicode))
- and NQ_FILE_SUFFIX != filename[-NQ_FILE_SUFFIX_LEN:]):
- filename = filename + NQ_FILE_SUFFIX
- self._location = filename
- self._alternative = dict()
- self._last_mod_time = 0
- self._last_check_time = 0
- self.deleted = False
- self.load_contents()
-
- def name(self):
- """ The name of the query. """
- return self._name
-
- def get_modtime(self):
- """ Returns the mtime (last modified time) of the named query
- filename. For file-like objects, expect a modtime of 0"""
- if self._location and isinstance(self._location, (str, unicode)):
- return os.path.getmtime(self._location)
- return 0
-
- def load_contents(self):
- """ Loads and parses the named query file into self. Does
- nothing if self.location is nonexistant."""
- if self._location:
- if isinstance(self._location, (str, unicode)):
- contents = llsd.parse(open(self._location).read())
- else:
- # we probably have a file-like object. Godspeed!
- contents = llsd.parse(self._location.read())
- self._reference_contents(contents)
- # Check for alternative implementations
- try:
- for name, alt in self._contents['alternative'].items():
- nq = NamedQuery(name, None)
- nq._reference_contents(alt)
- self._alternative[name] = nq
- except KeyError, e:
- pass
- self._last_mod_time = self.get_modtime()
- self._last_check_time = time.time()
-
- def _reference_contents(self, contents):
- "Helper method which builds internal structure from parsed contents"
- self._contents = contents
- self._ttl = int(self._contents.get('ttl', 0))
- self._return_as_map = bool(self._contents.get('return_as_map', False))
- self._legacy_dbname = self._contents.get('legacy_dbname', None)
-
- # reset these before doing the sql conversion because we will
- # read them there. reset these while loading so we pick up
- # changes.
- self._around = set()
- self._append = set()
- self._integer = set()
- self._options = self._contents.get('dynamic_where', {})
- for key in self._options:
- if isinstance(self._options[key], basestring):
- self._options[key] = self._convert_sql(self._options[key])
- elif isinstance(self._options[key], list):
- lines = []
- for line in self._options[key]:
- lines.append(self._convert_sql(line))
- self._options[key] = lines
- else:
- moreopt = {}
- for kk in self._options[key]:
- moreopt[kk] = self._convert_sql(self._options[key][kk])
- self._options[key] = moreopt
- self._base_query = self._convert_sql(self._contents['base_query'])
- self._query_suffix = self._convert_sql(
- self._contents.get('query_suffix', ''))
-
- def _convert_sql(self, sql):
- """convert the parsed sql into a useful internal structure.
-
- This function has to turn the named query format into a pyformat
- style. It also has to look for %:name% and :name% and
- ready them for use in LIKE statements"""
- if sql:
- # This first sub is to properly escape any % signs that
- # are meant to be literally passed through to mysql in the
- # query. It leaves any %'s that are used for
- # like-expressions.
- expr = re.compile("(?<=[^a-zA-Z0-9_-])%(?=[^:])")
- sql = expr.sub('%%', sql)
-
- # This should tackle the rest of the %'s in the query, by
- # converting them to LIKE clauses.
- expr = re.compile("(%?):([a-zA-Z][a-zA-Z0-9_-]*)%")
- sql = expr.sub(self._prepare_like, sql)
- expr = re.compile("#:([a-zA-Z][a-zA-Z0-9_-]*)")
- sql = expr.sub(self._prepare_integer, sql)
- expr = re.compile(":([a-zA-Z][a-zA-Z0-9_-]*)")
- sql = expr.sub("%(\\1)s", sql)
- return sql
-
- def _prepare_like(self, match):
- """This function changes LIKE statement replace behavior
-
- It works by turning %:name% to %(_name_around)s and :name% to
- %(_name_append)s. Since a leading '_' is not a valid keyname
- input (enforced via unit tests), it will never clash with
- existing keys. Then, when building the statement, the query
- runner will generate corrected strings."""
- if match.group(1) == '%':
- # there is a leading % so this is treated as prefix/suffix
- self._around.add(match.group(2))
- return "%(" + self._build_around_key(match.group(2)) + ")s"
- else:
- # there is no leading %, so this is suffix only
- self._append.add(match.group(2))
- return "%(" + self._build_append_key(match.group(2)) + ")s"
-
- def _build_around_key(self, key):
- return "_" + key + "_around"
-
- def _build_append_key(self, key):
- return "_" + key + "_append"
-
- def _prepare_integer(self, match):
- """This function adjusts the sql for #:name replacements
-
- It works by turning #:name to %(_name_as_integer)s. Since a
- leading '_' is not a valid keyname input (enforced via unit
- tests), it will never clash with existing keys. Then, when
- building the statement, the query runner will generate
- corrected strings."""
- self._integer.add(match.group(1))
- return "%(" + self._build_integer_key(match.group(1)) + ")s"
-
- def _build_integer_key(self, key):
- return "_" + key + "_as_integer"
-
- def _strip_wildcards_to_list(self, value):
- """Take string, and strip out the LIKE special characters.
-
- Technically, this is database dependant, but postgresql and
- mysql use the same wildcards, and I am not aware of a general
- way to handle this. I think you need a sql statement of the
- form:
-
- LIKE_STRING( [ANY,ONE,str]... )
-
- which would treat ANY as their any string, and ONE as their
- single glyph, and str as something that needs database
- specific encoding to not allow any % or _ to affect the query.
-
- As it stands, I believe it's impossible to write a named query
- style interface which uses like to search the entire space of
- text available. Imagine the query:
-
- % of brain used by average linden
-
- In order to search for %, it must be escaped, so once you have
- escaped the string to not do wildcard searches, and be escaped
- for the database, and then prepended the wildcard you come
- back with one of:
-
- 1) %\% of brain used by average linden
- 2) %%% of brain used by average linden
-
- Then, when passed to the database to be escaped to be database
- safe, you get back:
-
- 1) %\\% of brain used by average linden
- : which means search for any character sequence, followed by a
- backslash, followed by any sequence, followed by ' of
- brain...'
- 2) %%% of brain used by average linden
- : which (I believe) means search for a % followed by any
- character sequence followed by 'of brain...'
-
- Neither of which is what we want!
-
- So, we need a vendor (or extention) for LIKE_STRING. Anyone
- want to write it?"""
- if isinstance(value, unicode):
- utf8_value = value
- else:
- utf8_value = unicode(value, "utf-8")
- esc_list = []
- remove_chars = set(u"%_")
- for glyph in utf8_value:
- if glyph in remove_chars:
- continue
- esc_list.append(glyph.encode("utf-8"))
- return esc_list
-
- def delete(self):
- """ Makes this query unusable by deleting all the members and
- setting the deleted member. This is desired when the on-disk
- query has been deleted but the in-memory copy remains."""
- # blow away all members except _name, _location, and deleted
- name, location = self._name, self._location
- for key in self.__dict__.keys():
- del self.__dict__[key]
- self.deleted = True
- self._name, self._location = name, location
-
- def ttl(self):
- """ Estimated time to live of this query. Used for web
- services to set the Expires header."""
- return self._ttl
-
- def legacy_dbname(self):
- return self._legacy_dbname
-
- def return_as_map(self):
- """ Returns true if this query is configured to return its
- results as a single map (as opposed to a list of maps, the
- normal behavior)."""
-
- return self._return_as_map
-
- def for_schema(self, db_name):
- "Look trough the alternates and return the correct query"
- if db_name is None:
- return self
- try:
- return self._alternative[db_name]
- except KeyError, e:
- pass
- return self
-
- def run(self, connection, params, expect_rows = None, use_dictcursor = True):
- """given a connection, run a named query with the params
-
- Note that this function will fetch ALL rows. We do this because it
- opens and closes the cursor to generate the values, and this
- isn't a generator so the cursor has no life beyond the method call.
-
- @param cursor The connection to use (this generates its own cursor for the query)
- @param name The name of the query to run
- @param params The parameters passed into the query
- @param expect_rows The number of rows expected. Set to 1 if return_as_map is true. Raises ExpectationFailed if the number of returned rows doesn't exactly match. Kind of a hack.
- @param use_dictcursor Set to false to use a normal cursor and manually convert the rows to dicts.
- @return Returns the result set as a list of dicts, or, if the named query has return_as_map set to true, returns a single dict.
- """
- if use_dictcursor:
- cursor = connection.cursor(MySQLdb.cursors.DictCursor)
- else:
- cursor = connection.cursor()
-
- full_query, params = self._construct_sql(params)
- if DEBUG:
- print "SQL:", self.sql(connection, params)
- rows = cursor.execute(full_query, params)
-
- # *NOTE: the expect_rows argument is a very cheesy way to get some
- # validation on the result set. If you want to add more expectation
- # logic, do something more object-oriented and flexible. Or use an ORM.
- if(self._return_as_map):
- expect_rows = 1
- if expect_rows is not None and rows != expect_rows:
- cursor.close()
- raise ExpectationFailed("Statement expected %s rows, got %s. Sql: '%s' %s" % (
- expect_rows, rows, full_query, params))
-
- # convert to dicts manually if we're not using a dictcursor
- if use_dictcursor:
- result_set = cursor.fetchall()
- else:
- if cursor.description is None:
- # an insert or something
- x = cursor.fetchall()
- cursor.close()
- return x
-
- names = [x[0] for x in cursor.description]
-
- result_set = []
- for row in cursor.fetchall():
- converted_row = {}
- for idx, col_name in enumerate(names):
- converted_row[col_name] = row[idx]
- result_set.append(converted_row)
-
- cursor.close()
- if self._return_as_map:
- return result_set[0]
- return result_set
-
- def _construct_sql(self, params):
- """ Returns a query string and a dictionary of parameters,
- suitable for directly passing to the execute() method."""
- self.refresh()
-
- # build the query from the options available and the params
- base_query = []
- base_query.append(self._base_query)
- for opt, extra_where in self._options.items():
- if type(extra_where) in (dict, list, tuple):
- if opt in params:
- base_query.append(extra_where[params[opt]])
- else:
- if opt in params and params[opt]:
- base_query.append(extra_where)
- if self._query_suffix:
- base_query.append(self._query_suffix)
- full_query = '\n'.join(base_query)
-
- # Go through the query and rewrite all of the ones with the
- # @:name syntax.
- rewrite = _RewriteQueryForArray(params)
- expr = re.compile("@%\(([a-zA-Z][a-zA-Z0-9_-]*)\)s")
- full_query = expr.sub(rewrite.operate, full_query)
- params.update(rewrite.new_params)
-
- # build out the params for like. We only have to do this
- # parameters which were detected to have ued the where syntax
- # during load.
- #
- # * treat the incoming string as utf-8
- # * strip wildcards
- # * append or prepend % as appropriate
- new_params = {}
- for key in params:
- if key in self._around:
- new_value = ['%']
- new_value.extend(self._strip_wildcards_to_list(params[key]))
- new_value.append('%')
- new_params[self._build_around_key(key)] = ''.join(new_value)
- if key in self._append:
- new_value = self._strip_wildcards_to_list(params[key])
- new_value.append('%')
- new_params[self._build_append_key(key)] = ''.join(new_value)
- if key in self._integer:
- new_params[self._build_integer_key(key)] = int(params[key])
- params.update(new_params)
-
- return full_query, params
-
- def sql(self, connection, params):
- """ Generates an SQL statement from the named query document
- and a dictionary of parameters.
-
- *NOTE: Only use for debugging, because it uses the
- non-standard MySQLdb 'literal' method.
- """
- if not DEBUG:
- import warnings
- warnings.warn("Don't use named_query.sql() when not debugging. Used on %s" % self._location)
- # do substitution using the mysql (non-standard) 'literal'
- # function to do the escaping.
- full_query, params = self._construct_sql(params)
- return full_query % connection.literal(params)
-
-
- def refresh(self):
- """ Refresh self from the file on the filesystem.
-
- This is optimized to be callable as frequently as you wish,
- without adding too much load. It does so by only stat-ing the
- file every N seconds, where N defaults to 5 and is
- configurable through the member _stat_interval_seconds. If the stat
- reveals that the file has changed, refresh will re-parse the
- contents of the file and use them to update the named query
- instance. If the stat reveals that the file has been deleted,
- refresh will call self.delete to make the in-memory
- representation unusable."""
- now = time.time()
- if(now - self._last_check_time > self._stat_interval_seconds):
- self._last_check_time = now
- try:
- modtime = self.get_modtime()
- if(modtime > self._last_mod_time):
- self.load_contents()
- except OSError, e:
- if e.errno == errno.ENOENT: # file not found
- self.delete() # clean up self
- raise # pass the exception along to the caller so they know that this query disappeared
-
-class NamedQueryManager(object):
- """ Manages the lifespan of NamedQuery objects, drawing from a
- directory hierarchy of named query documents.
-
- In practice this amounts to a memory cache of NamedQuery objects."""
-
- def __init__(self, named_queries_dir):
- """ Initializes a manager to look for named queries in a
- directory."""
- self._dir = os.path.abspath(os.path.realpath(named_queries_dir))
- self._cached_queries = {}
-
- def sql(self, connection, name, params):
- nq = self.get(name)
- return nq.sql(connection, params)
-
- def get(self, name):
- """ Returns a NamedQuery instance based on the name, either
- from memory cache, or by parsing from disk.
-
- The name is simply a relative path to the directory associated
- with the manager object. Before returning the instance, the
- NamedQuery object is cached in memory, so that subsequent
- accesses don't have to read from disk or do any parsing. This
- means that NamedQuery objects returned by this method are
- shared across all users of the manager object.
- NamedQuery.refresh is used to bring the NamedQuery objects in
- sync with the actual files on disk."""
- nq = self._cached_queries.get(name)
- if nq is None:
- nq = NamedQuery(name, os.path.join(self._dir, name))
- self._cached_queries[name] = nq
- else:
- try:
- nq.refresh()
- except OSError, e:
- if e.errno == errno.ENOENT: # file not found
- del self._cached_queries[name]
- raise # pass exception along to caller so they know that the query disappeared
-
- return nq
-
-class _RewriteQueryForArray(object):
- "Helper class for rewriting queries with the @:name syntax"
- def __init__(self, params):
- self.params = params
- self.new_params = dict()
-
- def operate(self, match):
- "Given a match, return the string that should be in use"
- key = match.group(1)
- value = self.params[key]
- if type(value) in (list,tuple):
- rv = []
- for idx in range(len(value)):
- # if the value@idx is array-like, we are
- # probably dealing with a VALUES
- new_key = "_%s_%s"%(key, str(idx))
- val_item = value[idx]
- if type(val_item) in (list, tuple, dict):
- if type(val_item) is dict:
- # this is because in Python, the order of
- # key, value retrieval from the dict is not
- # guaranteed to match what the input intended
- # and for VALUES, order is important.
- # TODO: Implemented ordered dict in LLSD parser?
- raise ExpectationFailed('Only lists/tuples allowed,\
- received dict')
- values_keys = []
- for value_idx, item in enumerate(val_item):
- # we want a key of the format :
- # key_#replacement_#value_row_#value_col
- # ugh... so if we are replacing 10 rows in user_note,
- # the first values clause would read (for @:user_notes) :-
- # ( :_user_notes_0_1_1, :_user_notes_0_1_2, :_user_notes_0_1_3 )
- # the input LLSD for VALUES will look like:
- # ...
- #
- # ...
- values_key = "%s_%s"%(new_key, value_idx)
- self.new_params[values_key] = item
- values_keys.append("%%(%s)s"%values_key)
- # now collapse all these new place holders enclosed in ()
- # from [':_key_0_1_1', ':_key_0_1_2', ':_key_0_1_3,...]
- # rv will have [ '(:_key_0_1_1, :_key_0_1_2, :_key_0_1_3)', ]
- # which is flattened a few lines below join(rv)
- rv.append('(%s)' % ','.join(values_keys))
- else:
- self.new_params[new_key] = val_item
- rv.append("%%(%s)s"%new_key)
- return ','.join(rv)
- else:
- # not something that can be expanded, so just drop the
- # leading @ in the front of the match. This will mean that
- # the single value we have, be it a string, int, whatever
- # (other than dict) will correctly show up, eg:
- #
- # where foo in (@:foobar) -- foobar is a string, so we get
- # where foo in (:foobar)
- return match.group(0)[1:]
diff --git a/indra/lib/python/indra/util/shutil2.py b/indra/lib/python/indra/util/shutil2.py
deleted file mode 100644
index 9e2e7a6ded..0000000000
--- a/indra/lib/python/indra/util/shutil2.py
+++ /dev/null
@@ -1,84 +0,0 @@
-'''
-@file shutil2.py
-@brief a better shutil.copytree replacement
-
-$LicenseInfo:firstyear=2007&license=mit$
-
-Copyright (c) 2007-2009, Linden Research, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-$/LicenseInfo$
-'''
-
-#
-# shutil2.py
-# Taken from http://www.scons.org/wiki/AccumulateBuilder
-# the stock copytree sucks because it insists that the
-# target dir not exist
-#
-
-import os.path
-import shutil
-
-def copytree(src, dest, symlinks=False):
- """My own copyTree which does not fail if the directory exists.
-
- Recursively copy a directory tree using copy2().
-
- If the optional symlinks flag is true, symbolic links in the
- source tree result in symbolic links in the destination tree; if
- it is false, the contents of the files pointed to by symbolic
- links are copied.
-
- Behavior is meant to be identical to GNU 'cp -R'.
- """
- def copyItems(src, dest, symlinks=False):
- """Function that does all the work.
-
- It is necessary to handle the two 'cp' cases:
- - destination does exist
- - destination does not exist
-
- See 'cp -R' documentation for more details
- """
- for item in os.listdir(src):
- srcPath = os.path.join(src, item)
- if os.path.isdir(srcPath):
- srcBasename = os.path.basename(srcPath)
- destDirPath = os.path.join(dest, srcBasename)
- if not os.path.exists(destDirPath):
- os.makedirs(destDirPath)
- copyItems(srcPath, destDirPath)
- elif os.path.islink(item) and symlinks:
- linkto = os.readlink(item)
- os.symlink(linkto, dest)
- else:
- shutil.copy2(srcPath, dest)
-
- # case 'cp -R src/ dest/' where dest/ already exists
- if os.path.exists(dest):
- destPath = os.path.join(dest, os.path.basename(src))
- if not os.path.exists(destPath):
- os.makedirs(destPath)
- # case 'cp -R src/ dest/' where dest/ does not exist
- else:
- os.makedirs(dest)
- destPath = dest
- # actually copy the files
- copyItems(src, destPath)
diff --git a/indra/lib/python/indra/util/simperf_host_xml_parser.py b/indra/lib/python/indra/util/simperf_host_xml_parser.py
deleted file mode 100755
index 672c1050c2..0000000000
--- a/indra/lib/python/indra/util/simperf_host_xml_parser.py
+++ /dev/null
@@ -1,338 +0,0 @@
-#!/usr/bin/env python
-"""\
-@file simperf_host_xml_parser.py
-@brief Digest collector's XML dump and convert to simple dict/list structure
-
-$LicenseInfo:firstyear=2008&license=mit$
-
-Copyright (c) 2008-2009, Linden Research, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-$/LicenseInfo$
-"""
-
-import sys, os, getopt, time
-import simplejson
-from xml import sax
-
-
-def usage():
- print "Usage:"
- print sys.argv[0] + " [options]"
- print " Convert RRD's XML dump to JSON. Script to convert the simperf_host_collector-"
- print " generated RRD dump into JSON. Steps include converting selected named"
- print " fields from GAUGE type to COUNTER type by computing delta with preceding"
- print " values. Top-level named fields are:"
- print
- print " lastupdate Time (javascript timestamp) of last data sample"
- print " step Time in seconds between samples"
- print " ds Data specification (name/type) for each column"
- print " database Table of data samples, one time step per row"
- print
- print "Options:"
- print " -i, --in Input settings filename. (Default: stdin)"
- print " -o, --out Output settings filename. (Default: stdout)"
- print " -h, --help Print this message and exit."
- print
- print "Example: %s -i rrddump.xml -o rrddump.json" % sys.argv[0]
- print
- print "Interfaces:"
- print " class SimPerfHostXMLParser() # SAX content handler"
- print " def simperf_host_xml_fixup(parser) # post-parse value fixup"
-
-class SimPerfHostXMLParser(sax.handler.ContentHandler):
-
- def __init__(self):
- pass
-
- def startDocument(self):
- self.rrd_last_update = 0 # public
- self.rrd_step = 0 # public
- self.rrd_ds = [] # public
- self.rrd_records = [] # public
- self._rrd_level = 0
- self._rrd_parse_state = 0
- self._rrd_chars = ""
- self._rrd_capture = False
- self._rrd_ds_val = {}
- self._rrd_data_row = []
- self._rrd_data_row_has_nan = False
-
- def endDocument(self):
- pass
-
- # Nasty little ad-hoc state machine to extract the elements that are
- # necessary from the 'rrdtool dump' XML output. The same element
- # name '' is used for two different data sets so we need to pay
- # some attention to the actual structure to get the ones we want
- # and ignore the ones we don't.
-
- def startElement(self, name, attrs):
- self._rrd_level = self._rrd_level + 1
- self._rrd_capture = False
- if self._rrd_level == 1:
- if name == "rrd" and self._rrd_parse_state == 0:
- self._rrd_parse_state = 1 # In
- self._rrd_capture = True
- self._rrd_chars = ""
- elif self._rrd_level == 2:
- if self._rrd_parse_state == 1:
- if name == "lastupdate":
- self._rrd_parse_state = 2 # In
- self._rrd_capture = True
- self._rrd_chars = ""
- elif name == "step":
- self._rrd_parse_state = 3 # In
- self._rrd_capture = True
- self._rrd_chars = ""
- elif name == "ds":
- self._rrd_parse_state = 4 # In
- self._rrd_ds_val = {}
- self._rrd_chars = ""
- elif name == "rra":
- self._rrd_parse_state = 5 # In
- elif self._rrd_level == 3:
- if self._rrd_parse_state == 4:
- if name == "name":
- self._rrd_parse_state = 6 # In
- self._rrd_capture = True
- self._rrd_chars = ""
- elif name == "type":
- self._rrd_parse_state = 7 # In
- self._rrd_capture = True
- self._rrd_chars = ""
- elif self._rrd_parse_state == 5:
- if name == "database":
- self._rrd_parse_state = 8 # In
- elif self._rrd_level == 4:
- if self._rrd_parse_state == 8:
- if name == "row":
- self._rrd_parse_state = 9 # In
- self._rrd_data_row = []
- self._rrd_data_row_has_nan = False
- elif self._rrd_level == 5:
- if self._rrd_parse_state == 9:
- if name == "v":
- self._rrd_parse_state = 10 # In
- self._rrd_capture = True
- self._rrd_chars = ""
-
- def endElement(self, name):
- self._rrd_capture = False
- if self._rrd_parse_state == 10:
- self._rrd_capture = self._rrd_level == 6
- if self._rrd_level == 5:
- if self._rrd_chars == "NaN":
- self._rrd_data_row_has_nan = True
- else:
- self._rrd_data_row.append(self._rrd_chars)
- self._rrd_parse_state = 9 # In
- elif self._rrd_parse_state == 9:
- if self._rrd_level == 4:
- if not self._rrd_data_row_has_nan:
- self.rrd_records.append(self._rrd_data_row)
- self._rrd_parse_state = 8 # In
- elif self._rrd_parse_state == 8:
- if self._rrd_level == 3:
- self._rrd_parse_state = 5 # In
- elif self._rrd_parse_state == 7:
- if self._rrd_level == 3:
- self._rrd_ds_val["type"] = self._rrd_chars
- self._rrd_parse_state = 4 # In
- elif self._rrd_parse_state == 6:
- if self._rrd_level == 3:
- self._rrd_ds_val["name"] = self._rrd_chars
- self._rrd_parse_state = 4 # In
- elif self._rrd_parse_state == 5:
- if self._rrd_level == 2:
- self._rrd_parse_state = 1 # In
- elif self._rrd_parse_state == 4:
- if self._rrd_level == 2:
- self.rrd_ds.append(self._rrd_ds_val)
- self._rrd_parse_state = 1 # In
- elif self._rrd_parse_state == 3:
- if self._rrd_level == 2:
- self.rrd_step = long(self._rrd_chars)
- self._rrd_parse_state = 1 # In
- elif self._rrd_parse_state == 2:
- if self._rrd_level == 2:
- self.rrd_last_update = long(self._rrd_chars)
- self._rrd_parse_state = 1 # In
- elif self._rrd_parse_state == 1:
- if self._rrd_level == 1:
- self._rrd_parse_state = 0 # At top
-
- if self._rrd_level:
- self._rrd_level = self._rrd_level - 1
-
- def characters(self, content):
- if self._rrd_capture:
- self._rrd_chars = self._rrd_chars + content.strip()
-
-def _make_numeric(value):
- try:
- value = float(value)
- except:
- value = ""
- return value
-
-def simperf_host_xml_fixup(parser, filter_start_time = None, filter_end_time = None):
- # Fixup for GAUGE fields that are really COUNTS. They
- # were forced to GAUGE to try to disable rrdtool's
- # data interpolation/extrapolation for non-uniform time
- # samples.
- fixup_tags = [ "cpu_user",
- "cpu_nice",
- "cpu_sys",
- "cpu_idle",
- "cpu_waitio",
- "cpu_intr",
- # "file_active",
- # "file_free",
- # "inode_active",
- # "inode_free",
- "netif_in_kb",
- "netif_in_pkts",
- "netif_in_errs",
- "netif_in_drop",
- "netif_out_kb",
- "netif_out_pkts",
- "netif_out_errs",
- "netif_out_drop",
- "vm_page_in",
- "vm_page_out",
- "vm_swap_in",
- "vm_swap_out",
- #"vm_mem_total",
- #"vm_mem_used",
- #"vm_mem_active",
- #"vm_mem_inactive",
- #"vm_mem_free",
- #"vm_mem_buffer",
- #"vm_swap_cache",
- #"vm_swap_total",
- #"vm_swap_used",
- #"vm_swap_free",
- "cpu_interrupts",
- "cpu_switches",
- "cpu_forks" ]
-
- col_count = len(parser.rrd_ds)
- row_count = len(parser.rrd_records)
-
- # Process the last row separately, just to make all values numeric.
- for j in range(col_count):
- parser.rrd_records[row_count - 1][j] = _make_numeric(parser.rrd_records[row_count - 1][j])
-
- # Process all other row/columns.
- last_different_row = row_count - 1
- current_row = row_count - 2
- while current_row >= 0:
- # Check for a different value than the previous row. If everything is the same
- # then this is probably just a filler/bogus entry.
- is_different = False
- for j in range(col_count):
- parser.rrd_records[current_row][j] = _make_numeric(parser.rrd_records[current_row][j])
- if parser.rrd_records[current_row][j] != parser.rrd_records[last_different_row][j]:
- # We're good. This is a different row.
- is_different = True
-
- if not is_different:
- # This is a filler/bogus entry. Just ignore it.
- for j in range(col_count):
- parser.rrd_records[current_row][j] = float('nan')
- else:
- # Some tags need to be converted into deltas.
- for j in range(col_count):
- if parser.rrd_ds[j]["name"] in fixup_tags:
- parser.rrd_records[last_different_row][j] = \
- parser.rrd_records[last_different_row][j] - parser.rrd_records[current_row][j]
- last_different_row = current_row
-
- current_row -= 1
-
- # Set fixup_tags in the first row to 'nan' since they aren't useful anymore.
- for j in range(col_count):
- if parser.rrd_ds[j]["name"] in fixup_tags:
- parser.rrd_records[0][j] = float('nan')
-
- # Add a timestamp to each row and to the catalog. Format and name
- # chosen to match other simulator logging (hopefully).
- start_time = parser.rrd_last_update - (parser.rrd_step * (row_count - 1))
- # Build a filtered list of rrd_records if we are limited to a time range.
- filter_records = False
- if filter_start_time is not None or filter_end_time is not None:
- filter_records = True
- filtered_rrd_records = []
- if filter_start_time is None:
- filter_start_time = start_time * 1000
- if filter_end_time is None:
- filter_end_time = parser.rrd_last_update * 1000
-
- for i in range(row_count):
- record_timestamp = (start_time + (i * parser.rrd_step)) * 1000
- parser.rrd_records[i].insert(0, record_timestamp)
- if filter_records:
- if filter_start_time <= record_timestamp and record_timestamp <= filter_end_time:
- filtered_rrd_records.append(parser.rrd_records[i])
-
- if filter_records:
- parser.rrd_records = filtered_rrd_records
-
- parser.rrd_ds.insert(0, {"type": "GAUGE", "name": "javascript_timestamp"})
-
-
-def main(argv=None):
- opts, args = getopt.getopt(sys.argv[1:], "i:o:h", ["in=", "out=", "help"])
- input_file = sys.stdin
- output_file = sys.stdout
- for o, a in opts:
- if o in ("-i", "--in"):
- input_file = open(a, 'r')
- if o in ("-o", "--out"):
- output_file = open(a, 'w')
- if o in ("-h", "--help"):
- usage()
- sys.exit(0)
-
- # Using the SAX parser as it is at least 4X faster and far, far
- # smaller on this dataset than the DOM-based interface in xml.dom.minidom.
- # With SAX and a 5.4MB xml file, this requires about seven seconds of
- # wall-clock time and 32MB VSZ. With the DOM interface, about 22 seconds
- # and over 270MB VSZ.
-
- handler = SimPerfHostXMLParser()
- sax.parse(input_file, handler)
- if input_file != sys.stdin:
- input_file.close()
-
- # Various format fixups: string-to-num, gauge-to-counts, add
- # a time stamp, etc.
- simperf_host_xml_fixup(handler)
-
- # Create JSONable dict with interesting data and format/print it
- print >>output_file, simplejson.dumps({ "step" : handler.rrd_step,
- "lastupdate": handler.rrd_last_update * 1000,
- "ds" : handler.rrd_ds,
- "database" : handler.rrd_records })
-
- return 0
-
-if __name__ == "__main__":
- sys.exit(main())
diff --git a/indra/lib/python/indra/util/simperf_oprof_interface.py b/indra/lib/python/indra/util/simperf_oprof_interface.py
deleted file mode 100755
index 547d2f9980..0000000000
--- a/indra/lib/python/indra/util/simperf_oprof_interface.py
+++ /dev/null
@@ -1,167 +0,0 @@
-#!/usr/bin/env python
-"""\
-@file simperf_oprof_interface.py
-@brief Manage OProfile data collection on a host
-
-$LicenseInfo:firstyear=2008&license=mit$
-
-Copyright (c) 2008-2009, Linden Research, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-$/LicenseInfo$
-"""
-
-import sys, os, getopt
-import simplejson
-
-
-def usage():
- print "Usage:"
- print sys.argv[0] + " [options]"
- print " Digest the OProfile report forms that come out of the"
- print " simperf_oprof_ctl program's -r/--report command. The result"
- print " is an array of dictionaires with the following keys:"
- print
- print " symbol Name of sampled, calling, or called procedure"
- print " file Executable or library where symbol resides"
- print " percentage Percentage contribution to profile, calls or called"
- print " samples Sample count"
- print " calls Methods called by the method in question (full only)"
- print " called_by Methods calling the method (full only)"
- print
- print " For 'full' reports the two keys 'calls' and 'called_by' are"
- print " themselves arrays of dictionaries based on the first four keys."
- print
- print "Return Codes:"
- print " None. Aggressively digests everything. Will likely mung results"
- print " if a program or library has whitespace in its name."
- print
- print "Options:"
- print " -i, --in Input settings filename. (Default: stdin)"
- print " -o, --out Output settings filename. (Default: stdout)"
- print " -h, --help Print this message and exit."
- print
- print "Interfaces:"
- print " class SimPerfOProfileInterface()"
-
-class SimPerfOProfileInterface:
- def __init__(self):
- self.isBrief = True # public
- self.isValid = False # public
- self.result = [] # public
-
- def parse(self, input):
- in_samples = False
- for line in input:
- if in_samples:
- if line[0:6] == "------":
- self.isBrief = False
- self._parseFull(input)
- else:
- self._parseBrief(input, line)
- self.isValid = True
- return
- try:
- hd1, remain = line.split(None, 1)
- if hd1 == "samples":
- in_samples = True
- except ValueError:
- pass
-
- def _parseBrief(self, input, line1):
- try:
- fld1, fld2, fld3, fld4 = line1.split(None, 3)
- self.result.append({"samples" : fld1,
- "percentage" : fld2,
- "file" : fld3,
- "symbol" : fld4.strip("\n")})
- except ValueError:
- pass
- for line in input:
- try:
- fld1, fld2, fld3, fld4 = line.split(None, 3)
- self.result.append({"samples" : fld1,
- "percentage" : fld2,
- "file" : fld3,
- "symbol" : fld4.strip("\n")})
- except ValueError:
- pass
-
- def _parseFull(self, input):
- state = 0 # In 'called_by' section
- calls = []
- called_by = []
- current = {}
- for line in input:
- if line[0:6] == "------":
- if len(current):
- current["calls"] = calls
- current["called_by"] = called_by
- self.result.append(current)
- state = 0
- calls = []
- called_by = []
- current = {}
- else:
- try:
- fld1, fld2, fld3, fld4 = line.split(None, 3)
- tmp = {"samples" : fld1,
- "percentage" : fld2,
- "file" : fld3,
- "symbol" : fld4.strip("\n")}
- except ValueError:
- continue
- if line[0] != " ":
- current = tmp
- state = 1 # In 'calls' section
- elif state == 0:
- called_by.append(tmp)
- else:
- calls.append(tmp)
- if len(current):
- current["calls"] = calls
- current["called_by"] = called_by
- self.result.append(current)
-
-
-def main(argv=None):
- opts, args = getopt.getopt(sys.argv[1:], "i:o:h", ["in=", "out=", "help"])
- input_file = sys.stdin
- output_file = sys.stdout
- for o, a in opts:
- if o in ("-i", "--in"):
- input_file = open(a, 'r')
- if o in ("-o", "--out"):
- output_file = open(a, 'w')
- if o in ("-h", "--help"):
- usage()
- sys.exit(0)
-
- oprof = SimPerfOProfileInterface()
- oprof.parse(input_file)
- if input_file != sys.stdin:
- input_file.close()
-
- # Create JSONable dict with interesting data and format/print it
- print >>output_file, simplejson.dumps(oprof.result)
-
- return 0
-
-if __name__ == "__main__":
- sys.exit(main())
diff --git a/indra/lib/python/indra/util/simperf_proc_interface.py b/indra/lib/python/indra/util/simperf_proc_interface.py
deleted file mode 100755
index de061f68cc..0000000000
--- a/indra/lib/python/indra/util/simperf_proc_interface.py
+++ /dev/null
@@ -1,191 +0,0 @@
-#!/usr/bin/env python
-"""\
-@file simperf_proc_interface.py
-@brief Utility to extract log messages from *..llsd files containing performance statistics.
-
-$LicenseInfo:firstyear=2008&license=mit$
-
-Copyright (c) 2008-2009, Linden Research, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-$/LicenseInfo$
-"""
-
-# ----------------------------------------------------
-# Utility to extract log messages from *..llsd
-# files that contain performance statistics.
-
-# ----------------------------------------------------
-import sys, os
-
-if os.path.exists("setup-path.py"):
- execfile("setup-path.py")
-
-from indra.base import llsd
-
-DEFAULT_PATH="/dev/shm/simperf/"
-
-
-# ----------------------------------------------------
-# Pull out the stats and return a single document
-def parse_logfile(filename, target_column=None, verbose=False):
- full_doc = []
- # Open source temp log file. Let exceptions percolate up.
- sourcefile = open( filename,'r')
-
- if verbose:
- print "Reading " + filename
-
- # Parse and output all lines from the temp file
- for line in sourcefile.xreadlines():
- partial_doc = llsd.parse(line)
- if partial_doc is not None:
- if target_column is None:
- full_doc.append(partial_doc)
- else:
- trim_doc = { target_column: partial_doc[target_column] }
- if target_column != "fps":
- trim_doc[ 'fps' ] = partial_doc[ 'fps' ]
- trim_doc[ '/total_time' ] = partial_doc[ '/total_time' ]
- trim_doc[ 'utc_time' ] = partial_doc[ 'utc_time' ]
- full_doc.append(trim_doc)
-
- sourcefile.close()
- return full_doc
-
-# Extract just the meta info line, and the timestamp of the first/last frame entry.
-def parse_logfile_info(filename, verbose=False):
- # Open source temp log file. Let exceptions percolate up.
- sourcefile = open(filename, 'rU') # U is to open with Universal newline support
-
- if verbose:
- print "Reading " + filename
-
- # The first line is the meta info line.
- info_line = sourcefile.readline()
- if not info_line:
- sourcefile.close()
- return None
-
- # The rest of the lines are frames. Read the first and last to get the time range.
- info = llsd.parse( info_line )
- info['start_time'] = None
- info['end_time'] = None
- first_frame = sourcefile.readline()
- if first_frame:
- try:
- info['start_time'] = int(llsd.parse(first_frame)['timestamp'])
- except:
- pass
-
- # Read the file backwards to find the last two lines.
- sourcefile.seek(0, 2)
- file_size = sourcefile.tell()
- offset = 1024
- num_attempts = 0
- end_time = None
- if file_size < offset:
- offset = file_size
- while 1:
- sourcefile.seek(-1*offset, 2)
- read_str = sourcefile.read(offset)
- # Remove newline at the end
- if read_str[offset - 1] == '\n':
- read_str = read_str[0:-1]
- lines = read_str.split('\n')
- full_line = None
- if len(lines) > 2: # Got two line
- try:
- end_time = llsd.parse(lines[-1])['timestamp']
- except:
- # We couldn't parse this line. Try once more.
- try:
- end_time = llsd.parse(lines[-2])['timestamp']
- except:
- # Nope. Just move on.
- pass
- break
- if len(read_str) == file_size: # Reached the beginning
- break
- offset += 1024
-
- info['end_time'] = int(end_time)
-
- sourcefile.close()
- return info
-
-
-def parse_proc_filename(filename):
- try:
- name_as_list = filename.split(".")
- cur_stat_type = name_as_list[0].split("_")[0]
- cur_pid = name_as_list[1]
- except IndexError, ValueError:
- return (None, None)
- return (cur_pid, cur_stat_type)
-
-# ----------------------------------------------------
-def get_simstats_list(path=None):
- """ Return stats (pid, type) listed in _proc..llsd """
- if path is None:
- path = DEFAULT_PATH
- simstats_list = []
- for file_name in os.listdir(path):
- if file_name.endswith(".llsd") and file_name != "simperf_proc_config.llsd":
- simstats_info = parse_logfile_info(path + file_name)
- if simstats_info is not None:
- simstats_list.append(simstats_info)
- return simstats_list
-
-def get_log_info_list(pid=None, stat_type=None, path=None, target_column=None, verbose=False):
- """ Return data from all llsd files matching the pid and stat type """
- if path is None:
- path = DEFAULT_PATH
- log_info_list = {}
- for file_name in os.listdir ( path ):
- if file_name.endswith(".llsd") and file_name != "simperf_proc_config.llsd":
- (cur_pid, cur_stat_type) = parse_proc_filename(file_name)
- if cur_pid is None:
- continue
- if pid is not None and pid != cur_pid:
- continue
- if stat_type is not None and stat_type != cur_stat_type:
- continue
- log_info_list[cur_pid] = parse_logfile(path + file_name, target_column, verbose)
- return log_info_list
-
-def delete_simstats_files(pid=None, stat_type=None, path=None):
- """ Delete *..llsd files """
- if path is None:
- path = DEFAULT_PATH
- del_list = []
- for file_name in os.listdir(path):
- if file_name.endswith(".llsd") and file_name != "simperf_proc_config.llsd":
- (cur_pid, cur_stat_type) = parse_proc_filename(file_name)
- if cur_pid is None:
- continue
- if pid is not None and pid != cur_pid:
- continue
- if stat_type is not None and stat_type != cur_stat_type:
- continue
- del_list.append(cur_pid)
- # Allow delete related exceptions to percolate up if this fails.
- os.unlink(os.path.join(DEFAULT_PATH, file_name))
- return del_list
-
diff --git a/indra/lib/python/indra/util/term.py b/indra/lib/python/indra/util/term.py
deleted file mode 100644
index 8c316a1f12..0000000000
--- a/indra/lib/python/indra/util/term.py
+++ /dev/null
@@ -1,222 +0,0 @@
-'''
-@file term.py
-@brief a better shutil.copytree replacement
-
-$LicenseInfo:firstyear=2007&license=mit$
-
-Copyright (c) 2007-2009, Linden Research, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-$/LicenseInfo$
-'''
-
-#http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/475116
-
-import sys, re
-
-class TerminalController:
- """
- A class that can be used to portably generate formatted output to
- a terminal.
-
- `TerminalController` defines a set of instance variables whose
- values are initialized to the control sequence necessary to
- perform a given action. These can be simply included in normal
- output to the terminal:
-
- >>> term = TerminalController()
- >>> print 'This is '+term.GREEN+'green'+term.NORMAL
-
- Alternatively, the `render()` method can used, which replaces
- '${action}' with the string required to perform 'action':
-
- >>> term = TerminalController()
- >>> print term.render('This is ${GREEN}green${NORMAL}')
-
- If the terminal doesn't support a given action, then the value of
- the corresponding instance variable will be set to ''. As a
- result, the above code will still work on terminals that do not
- support color, except that their output will not be colored.
- Also, this means that you can test whether the terminal supports a
- given action by simply testing the truth value of the
- corresponding instance variable:
-
- >>> term = TerminalController()
- >>> if term.CLEAR_SCREEN:
- ... print 'This terminal supports clearning the screen.'
-
- Finally, if the width and height of the terminal are known, then
- they will be stored in the `COLS` and `LINES` attributes.
- """
- # Cursor movement:
- BOL = '' #: Move the cursor to the beginning of the line
- UP = '' #: Move the cursor up one line
- DOWN = '' #: Move the cursor down one line
- LEFT = '' #: Move the cursor left one char
- RIGHT = '' #: Move the cursor right one char
-
- # Deletion:
- CLEAR_SCREEN = '' #: Clear the screen and move to home position
- CLEAR_EOL = '' #: Clear to the end of the line.
- CLEAR_BOL = '' #: Clear to the beginning of the line.
- CLEAR_EOS = '' #: Clear to the end of the screen
-
- # Output modes:
- BOLD = '' #: Turn on bold mode
- BLINK = '' #: Turn on blink mode
- DIM = '' #: Turn on half-bright mode
- REVERSE = '' #: Turn on reverse-video mode
- NORMAL = '' #: Turn off all modes
-
- # Cursor display:
- HIDE_CURSOR = '' #: Make the cursor invisible
- SHOW_CURSOR = '' #: Make the cursor visible
-
- # Terminal size:
- COLS = None #: Width of the terminal (None for unknown)
- LINES = None #: Height of the terminal (None for unknown)
-
- # Foreground colors:
- BLACK = BLUE = GREEN = CYAN = RED = MAGENTA = YELLOW = WHITE = ''
-
- # Background colors:
- BG_BLACK = BG_BLUE = BG_GREEN = BG_CYAN = ''
- BG_RED = BG_MAGENTA = BG_YELLOW = BG_WHITE = ''
-
- _STRING_CAPABILITIES = """
- BOL=cr UP=cuu1 DOWN=cud1 LEFT=cub1 RIGHT=cuf1
- CLEAR_SCREEN=clear CLEAR_EOL=el CLEAR_BOL=el1 CLEAR_EOS=ed BOLD=bold
- BLINK=blink DIM=dim REVERSE=rev UNDERLINE=smul NORMAL=sgr0
- HIDE_CURSOR=cinvis SHOW_CURSOR=cnorm""".split()
- _COLORS = """BLACK BLUE GREEN CYAN RED MAGENTA YELLOW WHITE""".split()
- _ANSICOLORS = "BLACK RED GREEN YELLOW BLUE MAGENTA CYAN WHITE".split()
-
- def __init__(self, term_stream=sys.stdout):
- """
- Create a `TerminalController` and initialize its attributes
- with appropriate values for the current terminal.
- `term_stream` is the stream that will be used for terminal
- output; if this stream is not a tty, then the terminal is
- assumed to be a dumb terminal (i.e., have no capabilities).
- """
- # Curses isn't available on all platforms
- try: import curses
- except: return
-
- # If the stream isn't a tty, then assume it has no capabilities.
- if not term_stream.isatty(): return
-
- # Check the terminal type. If we fail, then assume that the
- # terminal has no capabilities.
- try: curses.setupterm()
- except: return
-
- # Look up numeric capabilities.
- self.COLS = curses.tigetnum('cols')
- self.LINES = curses.tigetnum('lines')
-
- # Look up string capabilities.
- for capability in self._STRING_CAPABILITIES:
- (attrib, cap_name) = capability.split('=')
- setattr(self, attrib, self._tigetstr(cap_name) or '')
-
- # Colors
- set_fg = self._tigetstr('setf')
- if set_fg:
- for i,color in zip(range(len(self._COLORS)), self._COLORS):
- setattr(self, color, curses.tparm(set_fg, i) or '')
- set_fg_ansi = self._tigetstr('setaf')
- if set_fg_ansi:
- for i,color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS):
- setattr(self, color, curses.tparm(set_fg_ansi, i) or '')
- set_bg = self._tigetstr('setb')
- if set_bg:
- for i,color in zip(range(len(self._COLORS)), self._COLORS):
- setattr(self, 'BG_'+color, curses.tparm(set_bg, i) or '')
- set_bg_ansi = self._tigetstr('setab')
- if set_bg_ansi:
- for i,color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS):
- setattr(self, 'BG_'+color, curses.tparm(set_bg_ansi, i) or '')
-
- def _tigetstr(self, cap_name):
- # String capabilities can include "delays" of the form "$<2>".
- # For any modern terminal, we should be able to just ignore
- # these, so strip them out.
- import curses
- cap = curses.tigetstr(cap_name) or ''
- return re.sub(r'\$<\d+>[/*]?', '', cap)
-
- def render(self, template):
- """
- Replace each $-substitutions in the given template string with
- the corresponding terminal control string (if it's defined) or
- '' (if it's not).
- """
- return re.sub(r'\$\$|\${\w+}', self._render_sub, template)
-
- def _render_sub(self, match):
- s = match.group()
- if s == '$$': return s
- else: return getattr(self, s[2:-1])
-
-#######################################################################
-# Example use case: progress bar
-#######################################################################
-
-class ProgressBar:
- """
- A 3-line progress bar, which looks like::
-
- Header
- 20% [===========----------------------------------]
- progress message
-
- The progress bar is colored, if the terminal supports color
- output; and adjusts to the width of the terminal.
- """
- BAR = '%3d%% ${GREEN}[${BOLD}%s%s${NORMAL}${GREEN}]${NORMAL}\n'
- HEADER = '${BOLD}${CYAN}%s${NORMAL}\n\n'
-
- def __init__(self, term, header):
- self.term = term
- if not (self.term.CLEAR_EOL and self.term.UP and self.term.BOL):
- raise ValueError("Terminal isn't capable enough -- you "
- "should use a simpler progress dispaly.")
- self.width = self.term.COLS or 75
- self.bar = term.render(self.BAR)
- self.header = self.term.render(self.HEADER % header.center(self.width))
- self.cleared = 1 #: true if we haven't drawn the bar yet.
- self.update(0, '')
-
- def update(self, percent, message):
- if self.cleared:
- sys.stdout.write(self.header)
- self.cleared = 0
- n = int((self.width-10)*percent)
- sys.stdout.write(
- self.term.BOL + self.term.UP + self.term.CLEAR_EOL +
- (self.bar % (100*percent, '='*n, '-'*(self.width-10-n))) +
- self.term.CLEAR_EOL + message.center(self.width))
-
- def clear(self):
- if not self.cleared:
- sys.stdout.write(self.term.BOL + self.term.CLEAR_EOL +
- self.term.UP + self.term.CLEAR_EOL +
- self.term.UP + self.term.CLEAR_EOL)
- self.cleared = 1
diff --git a/indra/lib/python/indra/util/test_win32_manifest.py b/indra/lib/python/indra/util/test_win32_manifest.py
index 0532cb0065..9863b97778 100644
--- a/indra/lib/python/indra/util/test_win32_manifest.py
+++ b/indra/lib/python/indra/util/test_win32_manifest.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python2
"""\
@file test_win32_manifest.py
@brief Test an assembly binding version and uniqueness in a windows dll or exe.
diff --git a/indra/lib/python/uuid.py b/indra/lib/python/uuid.py
deleted file mode 100644
index 0bc21a35f8..0000000000
--- a/indra/lib/python/uuid.py
+++ /dev/null
@@ -1,487 +0,0 @@
-r"""UUID objects (universally unique identifiers) according to RFC 4122.
-
-This module provides immutable UUID objects (class UUID) and the functions
-uuid1(), uuid3(), uuid4(), uuid5() for generating version 1, 3, 4, and 5
-UUIDs as specified in RFC 4122.
-
-If all you want is a unique ID, you should probably call uuid1() or uuid4().
-Note that uuid1() may compromise privacy since it creates a UUID containing
-the computer's network address. uuid4() creates a random UUID.
-
-Typical usage:
-
- >>> import uuid
-
- # make a UUID based on the host ID and current time
- >>> uuid.uuid1()
- UUID('a8098c1a-f86e-11da-bd1a-00112444be1e')
-
- # make a UUID using an MD5 hash of a namespace UUID and a name
- >>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org')
- UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e')
-
- # make a random UUID
- >>> uuid.uuid4()
- UUID('16fd2706-8baf-433b-82eb-8c7fada847da')
-
- # make a UUID using a SHA-1 hash of a namespace UUID and a name
- >>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org')
- UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d')
-
- # make a UUID from a string of hex digits (braces and hyphens ignored)
- >>> x = uuid.UUID('{00010203-0405-0607-0809-0a0b0c0d0e0f}')
-
- # convert a UUID to a string of hex digits in standard form
- >>> str(x)
- '00010203-0405-0607-0809-0a0b0c0d0e0f'
-
- # get the raw 16 bytes of the UUID
- >>> x.bytes
- '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f'
-
- # make a UUID from a 16-byte string
- >>> uuid.UUID(bytes=x.bytes)
- UUID('00010203-0405-0607-0809-0a0b0c0d0e0f')
-
-This module works with Python 2.3 or higher."""
-
-__author__ = 'Ka-Ping Yee '
-__date__ = '$Date: 2006/06/12 23:15:40 $'.split()[1].replace('/', '-')
-__version__ = '$Revision: 1.30 $'.split()[1]
-
-RESERVED_NCS, RFC_4122, RESERVED_MICROSOFT, RESERVED_FUTURE = [
- 'reserved for NCS compatibility', 'specified in RFC 4122',
- 'reserved for Microsoft compatibility', 'reserved for future definition']
-
-class UUID(object):
- """Instances of the UUID class represent UUIDs as specified in RFC 4122.
- UUID objects are immutable, hashable, and usable as dictionary keys.
- Converting a UUID to a string with str() yields something in the form
- '12345678-1234-1234-1234-123456789abc'. The UUID constructor accepts
- four possible forms: a similar string of hexadecimal digits, or a
- string of 16 raw bytes as an argument named 'bytes', or a tuple of
- six integer fields (with 32-bit, 16-bit, 16-bit, 8-bit, 8-bit, and
- 48-bit values respectively) as an argument named 'fields', or a single
- 128-bit integer as an argument named 'int'.
-
- UUIDs have these read-only attributes:
-
- bytes the UUID as a 16-byte string
-
- fields a tuple of the six integer fields of the UUID,
- which are also available as six individual attributes
- and two derived attributes:
-
- time_low the first 32 bits of the UUID
- time_mid the next 16 bits of the UUID
- time_hi_version the next 16 bits of the UUID
- clock_seq_hi_variant the next 8 bits of the UUID
- clock_seq_low the next 8 bits of the UUID
- node the last 48 bits of the UUID
-
- time the 60-bit timestamp
- clock_seq the 14-bit sequence number
-
- hex the UUID as a 32-character hexadecimal string
-
- int the UUID as a 128-bit integer
-
- urn the UUID as a URN as specified in RFC 4122
-
- variant the UUID variant (one of the constants RESERVED_NCS,
- RFC_4122, RESERVED_MICROSOFT, or RESERVED_FUTURE)
-
- version the UUID version number (1 through 5, meaningful only
- when the variant is RFC_4122)
- """
-
- def __init__(self, hex=None, bytes=None, fields=None, int=None,
- version=None):
- r"""Create a UUID from either a string of 32 hexadecimal digits,
- a string of 16 bytes as the 'bytes' argument, a tuple of six
- integers (32-bit time_low, 16-bit time_mid, 16-bit time_hi_version,
- 8-bit clock_seq_hi_variant, 8-bit clock_seq_low, 48-bit node) as
- the 'fields' argument, or a single 128-bit integer as the 'int'
- argument. When a string of hex digits is given, curly braces,
- hyphens, and a URN prefix are all optional. For example, these
- expressions all yield the same UUID:
-
- UUID('{12345678-1234-5678-1234-567812345678}')
- UUID('12345678123456781234567812345678')
- UUID('urn:uuid:12345678-1234-5678-1234-567812345678')
- UUID(bytes='\x12\x34\x56\x78'*4)
- UUID(fields=(0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x567812345678))
- UUID(int=0x12345678123456781234567812345678)
-
- Exactly one of 'hex', 'bytes', 'fields', or 'int' must be given.
- The 'version' argument is optional; if given, the resulting UUID
- will have its variant and version number set according to RFC 4122,
- overriding bits in the given 'hex', 'bytes', 'fields', or 'int'.
- """
-
- if [hex, bytes, fields, int].count(None) != 3:
- raise TypeError('need just one of hex, bytes, fields, or int')
- if hex is not None:
- hex = hex.replace('urn:', '').replace('uuid:', '')
- hex = hex.strip('{}').replace('-', '')
- if len(hex) != 32:
- raise ValueError('badly formed hexadecimal UUID string')
- int = long(hex, 16)
- if bytes is not None:
- if len(bytes) != 16:
- raise ValueError('bytes is not a 16-char string')
- int = long(('%02x'*16) % tuple(map(ord, bytes)), 16)
- if fields is not None:
- if len(fields) != 6:
- raise ValueError('fields is not a 6-tuple')
- (time_low, time_mid, time_hi_version,
- clock_seq_hi_variant, clock_seq_low, node) = fields
- if not 0 <= time_low < 1<<32L:
- raise ValueError('field 1 out of range (need a 32-bit value)')
- if not 0 <= time_mid < 1<<16L:
- raise ValueError('field 2 out of range (need a 16-bit value)')
- if not 0 <= time_hi_version < 1<<16L:
- raise ValueError('field 3 out of range (need a 16-bit value)')
- if not 0 <= clock_seq_hi_variant < 1<<8L:
- raise ValueError('field 4 out of range (need an 8-bit value)')
- if not 0 <= clock_seq_low < 1<<8L:
- raise ValueError('field 5 out of range (need an 8-bit value)')
- if not 0 <= node < 1<<48L:
- raise ValueError('field 6 out of range (need a 48-bit value)')
- clock_seq = (clock_seq_hi_variant << 8L) | clock_seq_low
- int = ((time_low << 96L) | (time_mid << 80L) |
- (time_hi_version << 64L) | (clock_seq << 48L) | node)
- if int is not None:
- if not 0 <= int < 1<<128L:
- raise ValueError('int is out of range (need a 128-bit value)')
- if version is not None:
- if not 1 <= version <= 5:
- raise ValueError('illegal version number')
- # Set the variant to RFC 4122.
- int &= ~(0xc000 << 48L)
- int |= 0x8000 << 48L
- # Set the version number.
- int &= ~(0xf000 << 64L)
- int |= version << 76L
- self.__dict__['int'] = int
-
- def __cmp__(self, other):
- if isinstance(other, UUID):
- return cmp(self.int, other.int)
- return NotImplemented
-
- def __hash__(self):
- return hash(self.int)
-
- def __int__(self):
- return self.int
-
- def __repr__(self):
- return 'UUID(%r)' % str(self)
-
- def __setattr__(self, name, value):
- raise TypeError('UUID objects are immutable')
-
- def __str__(self):
- hex = '%032x' % self.int
- return '%s-%s-%s-%s-%s' % (
- hex[:8], hex[8:12], hex[12:16], hex[16:20], hex[20:])
-
- def get_bytes(self):
- bytes = ''
- for shift in range(0, 128, 8):
- bytes = chr((self.int >> shift) & 0xff) + bytes
- return bytes
-
- bytes = property(get_bytes)
-
- def get_fields(self):
- return (self.time_low, self.time_mid, self.time_hi_version,
- self.clock_seq_hi_variant, self.clock_seq_low, self.node)
-
- fields = property(get_fields)
-
- def get_time_low(self):
- return self.int >> 96L
-
- time_low = property(get_time_low)
-
- def get_time_mid(self):
- return (self.int >> 80L) & 0xffff
-
- time_mid = property(get_time_mid)
-
- def get_time_hi_version(self):
- return (self.int >> 64L) & 0xffff
-
- time_hi_version = property(get_time_hi_version)
-
- def get_clock_seq_hi_variant(self):
- return (self.int >> 56L) & 0xff
-
- clock_seq_hi_variant = property(get_clock_seq_hi_variant)
-
- def get_clock_seq_low(self):
- return (self.int >> 48L) & 0xff
-
- clock_seq_low = property(get_clock_seq_low)
-
- def get_time(self):
- return (((self.time_hi_version & 0x0fffL) << 48L) |
- (self.time_mid << 32L) | self.time_low)
-
- time = property(get_time)
-
- def get_clock_seq(self):
- return (((self.clock_seq_hi_variant & 0x3fL) << 8L) |
- self.clock_seq_low)
-
- clock_seq = property(get_clock_seq)
-
- def get_node(self):
- return self.int & 0xffffffffffff
-
- node = property(get_node)
-
- def get_hex(self):
- return '%032x' % self.int
-
- hex = property(get_hex)
-
- def get_urn(self):
- return 'urn:uuid:' + str(self)
-
- urn = property(get_urn)
-
- def get_variant(self):
- if not self.int & (0x8000 << 48L):
- return RESERVED_NCS
- elif not self.int & (0x4000 << 48L):
- return RFC_4122
- elif not self.int & (0x2000 << 48L):
- return RESERVED_MICROSOFT
- else:
- return RESERVED_FUTURE
-
- variant = property(get_variant)
-
- def get_version(self):
- # The version bits are only meaningful for RFC 4122 UUIDs.
- if self.variant == RFC_4122:
- return int((self.int >> 76L) & 0xf)
-
- version = property(get_version)
-
-def _ifconfig_getnode():
- """Get the hardware address on Unix by running ifconfig."""
- import os
- for dir in ['', '/sbin/', '/usr/sbin']:
- try:
- path = os.path.join(dir, 'ifconfig')
- if os.path.exists(path):
- pipe = os.popen(path)
- else:
- continue
- except IOError:
- continue
- for line in pipe:
- words = line.lower().split()
- for i in range(len(words)):
- if words[i] in ['hwaddr', 'ether']:
- return int(words[i + 1].replace(':', ''), 16)
-
-def _ipconfig_getnode():
- """Get the hardware address on Windows by running ipconfig.exe."""
- import os, re
- dirs = ['', r'c:\windows\system32', r'c:\winnt\system32']
- try:
- import ctypes
- buffer = ctypes.create_string_buffer(300)
- ctypes.windll.kernel32.GetSystemDirectoryA(buffer, 300)
- dirs.insert(0, buffer.value.decode('mbcs'))
- except:
- pass
- for dir in dirs:
- try:
- pipe = os.popen(os.path.join(dir, 'ipconfig') + ' /all')
- except IOError:
- continue
- for line in pipe:
- value = line.split(':')[-1].strip().lower()
- if re.match('([0-9a-f][0-9a-f]-){5}[0-9a-f][0-9a-f]', value):
- return int(value.replace('-', ''), 16)
-
-def _netbios_getnode():
- """Get the hardware address on Windows using NetBIOS calls.
- See http://support.microsoft.com/kb/118623 for details."""
- import win32wnet, netbios
- ncb = netbios.NCB()
- ncb.Command = netbios.NCBENUM
- ncb.Buffer = adapters = netbios.LANA_ENUM()
- adapters._pack()
- if win32wnet.Netbios(ncb) != 0:
- return
- adapters._unpack()
- for i in range(adapters.length):
- ncb.Reset()
- ncb.Command = netbios.NCBRESET
- ncb.Lana_num = ord(adapters.lana[i])
- if win32wnet.Netbios(ncb) != 0:
- continue
- ncb.Reset()
- ncb.Command = netbios.NCBASTAT
- ncb.Lana_num = ord(adapters.lana[i])
- ncb.Callname = '*'.ljust(16)
- ncb.Buffer = status = netbios.ADAPTER_STATUS()
- if win32wnet.Netbios(ncb) != 0:
- continue
- status._unpack()
- bytes = map(ord, status.adapter_address)
- return ((bytes[0]<<40L) + (bytes[1]<<32L) + (bytes[2]<<24L) +
- (bytes[3]<<16L) + (bytes[4]<<8L) + bytes[5])
-
-# Thanks to Thomas Heller for ctypes and for his help with its use here.
-
-# If ctypes is available, use it to find system routines for UUID generation.
-_uuid_generate_random = _uuid_generate_time = _UuidCreate = None
-try:
- import ctypes, ctypes.util
- _buffer = ctypes.create_string_buffer(16)
-
- # The uuid_generate_* routines are provided by libuuid on at least
- # Linux and FreeBSD, and provided by libc on Mac OS X.
- for libname in ['uuid', 'c']:
- try:
- lib = ctypes.CDLL(ctypes.util.find_library(libname))
- except:
- continue
- if hasattr(lib, 'uuid_generate_random'):
- _uuid_generate_random = lib.uuid_generate_random
- if hasattr(lib, 'uuid_generate_time'):
- _uuid_generate_time = lib.uuid_generate_time
-
- # On Windows prior to 2000, UuidCreate gives a UUID containing the
- # hardware address. On Windows 2000 and later, UuidCreate makes a
- # random UUID and UuidCreateSequential gives a UUID containing the
- # hardware address. These routines are provided by the RPC runtime.
- try:
- lib = ctypes.windll.rpcrt4
- except:
- lib = None
- _UuidCreate = getattr(lib, 'UuidCreateSequential',
- getattr(lib, 'UuidCreate', None))
-except:
- pass
-
-def _unixdll_getnode():
- """Get the hardware address on Unix using ctypes."""
- _uuid_generate_time(_buffer)
- return UUID(bytes=_buffer.raw).node
-
-def _windll_getnode():
- """Get the hardware address on Windows using ctypes."""
- if _UuidCreate(_buffer) == 0:
- return UUID(bytes=_buffer.raw).node
-
-def _random_getnode():
- """Get a random node ID, with eighth bit set as suggested by RFC 4122."""
- import random
- return random.randrange(0, 1<<48L) | 0x010000000000L
-
-_node = None
-
-def getnode():
- """Get the hardware address as a 48-bit integer. The first time this
- runs, it may launch a separate program, which could be quite slow. If
- all attempts to obtain the hardware address fail, we choose a random
- 48-bit number with its eighth bit set to 1 as recommended in RFC 4122."""
-
- global _node
- if _node is not None:
- return _node
-
- import sys
- if sys.platform == 'win32':
- getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode]
- else:
- getters = [_unixdll_getnode, _ifconfig_getnode]
-
- for getter in getters + [_random_getnode]:
- try:
- _node = getter()
- except:
- continue
- if _node is not None:
- return _node
-
-def uuid1(node=None, clock_seq=None):
- """Generate a UUID from a host ID, sequence number, and the current time.
- If 'node' is not given, getnode() is used to obtain the hardware
- address. If 'clock_seq' is given, it is used as the sequence number;
- otherwise a random 14-bit sequence number is chosen."""
-
- # When the system provides a version-1 UUID generator, use it (but don't
- # use UuidCreate here because its UUIDs don't conform to RFC 4122).
- if _uuid_generate_time and node is clock_seq is None:
- _uuid_generate_time(_buffer)
- return UUID(bytes=_buffer.raw)
-
- import time
- nanoseconds = int(time.time() * 1e9)
- # 0x01b21dd213814000 is the number of 100-ns intervals between the
- # UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00.
- timestamp = int(nanoseconds/100) + 0x01b21dd213814000L
- if clock_seq is None:
- import random
- clock_seq = random.randrange(1<<14L) # instead of stable storage
- time_low = timestamp & 0xffffffffL
- time_mid = (timestamp >> 32L) & 0xffffL
- time_hi_version = (timestamp >> 48L) & 0x0fffL
- clock_seq_low = clock_seq & 0xffL
- clock_seq_hi_variant = (clock_seq >> 8L) & 0x3fL
- if node is None:
- node = getnode()
- return UUID(fields=(time_low, time_mid, time_hi_version,
- clock_seq_hi_variant, clock_seq_low, node), version=1)
-
-def uuid3(namespace, name):
- """Generate a UUID from the MD5 hash of a namespace UUID and a name."""
- try:
- # Python 2.6
- from hashlib import md5
- except ImportError:
- # Python 2.5 and earlier
- from md5 import new as md5
-
- hash = md5(namespace.bytes + name).digest()
- return UUID(bytes=hash[:16], version=3)
-
-def uuid4():
- """Generate a random UUID."""
-
- # When the system provides a version-4 UUID generator, use it.
- if _uuid_generate_random:
- _uuid_generate_random(_buffer)
- return UUID(bytes=_buffer.raw)
-
- # Otherwise, get randomness from urandom or the 'random' module.
- try:
- import os
- return UUID(bytes=os.urandom(16), version=4)
- except:
- import random
- bytes = [chr(random.randrange(256)) for i in range(16)]
- return UUID(bytes=bytes, version=4)
-
-def uuid5(namespace, name):
- """Generate a UUID from the SHA-1 hash of a namespace UUID and a name."""
- import sha
- hash = sha.sha(namespace.bytes + name).digest()
- return UUID(bytes=hash[:16], version=5)
-
-# The following standard UUIDs are for use with uuid3() or uuid5().
-
-NAMESPACE_DNS = UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
-NAMESPACE_URL = UUID('6ba7b811-9dad-11d1-80b4-00c04fd430c8')
-NAMESPACE_OID = UUID('6ba7b812-9dad-11d1-80b4-00c04fd430c8')
-NAMESPACE_X500 = UUID('6ba7b814-9dad-11d1-80b4-00c04fd430c8')
diff --git a/indra/libhacd/hacdMicroAllocator.cpp b/indra/libhacd/hacdMicroAllocator.cpp
index 47562f6a4f..664b5e8c66 100644
--- a/indra/libhacd/hacdMicroAllocator.cpp
+++ b/indra/libhacd/hacdMicroAllocator.cpp
@@ -436,7 +436,7 @@ class MyMicroAllocator : public MicroAllocator, public MicroChunkUpdate, public
}
- ~MyMicroAllocator(void)
+ virtual ~MyMicroAllocator()
{
if ( mMicroChunks )
{
@@ -746,7 +746,7 @@ class MyHeapManager : public MicroHeap, public HeapManager
mMicro = createMicroAllocator(this,defaultChunkSize);
}
- ~MyHeapManager(void)
+ virtual ~MyHeapManager()
{
releaseMicroAllocator(mMicro);
}
diff --git a/indra/libndhacd/CMakeLists.txt b/indra/libndhacd/CMakeLists.txt
index 28c4d2f9a7..ce520fbdc6 100644
--- a/indra/libndhacd/CMakeLists.txt
+++ b/indra/libndhacd/CMakeLists.txt
@@ -33,3 +33,8 @@ set_source_files_properties(${libndhacd_HEADER_FILES}
add_library( nd_hacdConvexDecomposition STATIC ${libndhacd_SOURCE_FILES} ${libndhacd_HEADER_FILES})
+target_link_libraries(
+ nd_hacdConvexDecomposition
+ PUBLIC
+ llcommon
+ )
diff --git a/indra/libopenjpeg/CMakeLists.txt b/indra/libopenjpeg/CMakeLists.txt
index da21fe8dcb..9e41149eae 100644
--- a/indra/libopenjpeg/CMakeLists.txt
+++ b/indra/libopenjpeg/CMakeLists.txt
@@ -26,6 +26,7 @@ set(openjpeg_SOURCE_FILES
mct.c
mqc.c
openjpeg.c
+ opj_malloc.c
phix_manager.c
pi.c
ppix_manager.c
diff --git a/indra/libopenjpeg/dwt.c b/indra/libopenjpeg/dwt.c
index 0fbfc2033f..e641f15492 100644
--- a/indra/libopenjpeg/dwt.c
+++ b/indra/libopenjpeg/dwt.c
@@ -31,11 +31,16 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+#define OPJ_SKIP_POISON
+#include "opj_includes.h"
+
#ifdef __SSE__
#include
#endif
-#include "opj_includes.h"
+#if defined(__GNUC__)
+#pragma GCC poison malloc calloc realloc free
+#endif
/** @defgroup DWT DWT - Implementation of a discrete wavelet transform */
/*@{*/
@@ -499,7 +504,7 @@ void dwt_calc_explicit_stepsizes(opj_tccp_t * tccp, int prec) {
/* */
/* Determine maximum computed resolution level for inverse wavelet transform */
/* */
-static int dwt_decode_max_resolution(opj_tcd_resolution_t* restrict r, int i) {
+static int dwt_decode_max_resolution(opj_tcd_resolution_t* OPJ_RESTRICT r, int i) {
int mr = 1;
int w;
while( --i ) {
@@ -531,7 +536,7 @@ static void dwt_decode_tile(opj_tcd_tilecomp_t* tilec, int numres, DWT1DFN dwt_1
v.mem = h.mem;
while( --numres) {
- int * restrict tiledp = tilec->data;
+ int * OPJ_RESTRICT tiledp = tilec->data;
int j;
++tr;
@@ -565,48 +570,49 @@ static void dwt_decode_tile(opj_tcd_tilecomp_t* tilec, int numres, DWT1DFN dwt_1
opj_aligned_free(h.mem);
}
-static void v4dwt_interleave_h(v4dwt_t* restrict w, float* restrict a, int x, int size){
- float* restrict bi = (float*) (w->wavelet + w->cas);
+static void v4dwt_interleave_h(v4dwt_t* OPJ_RESTRICT w, float* OPJ_RESTRICT a, int x, int size) {
+ float* OPJ_RESTRICT bi = (float*)(w->wavelet + w->cas);
int count = w->sn;
int i, k;
- for(k = 0; k < 2; ++k){
- if (count + 3 * x < size && ((size_t) a & 0x0f) == 0 && ((size_t) bi & 0x0f) == 0 && (x & 0x0f) == 0) {
+ for (k = 0; k < 2; ++k) {
+ if (count + 3 * x < size && ((size_t)a & 0x0f) == 0 && ((size_t)bi & 0x0f) == 0 && (x & 0x0f) == 0) {
/* Fast code path */
- for(i = 0; i < count; ++i){
+ for (i = 0; i < count; ++i) {
int j = i;
- bi[i*8 ] = a[j];
+ bi[i * 8] = a[j];
j += x;
- bi[i*8 + 1] = a[j];
+ bi[i * 8 + 1] = a[j];
j += x;
- bi[i*8 + 2] = a[j];
+ bi[i * 8 + 2] = a[j];
j += x;
- bi[i*8 + 3] = a[j];
+ bi[i * 8 + 3] = a[j];
}
- } else {
- /* Slow code path */
- for(i = 0; i < count; ++i){
- int j = i;
- bi[i*8 ] = a[j];
- j += x;
- if(j > size) continue;
- bi[i*8 + 1] = a[j];
- j += x;
- if(j > size) continue;
- bi[i*8 + 2] = a[j];
- j += x;
- if(j > size) continue;
- bi[i*8 + 3] = a[j];
}
+ else {
+ /* Slow code path */
+ for (i = 0; i < count; ++i) {
+ int j = i;
+ bi[i * 8] = a[j];
+ j += x;
+ if (j > size) continue;
+ bi[i * 8 + 1] = a[j];
+ j += x;
+ if (j > size) continue;
+ bi[i * 8 + 2] = a[j];
+ j += x;
+ if (j > size) continue;
+ bi[i * 8 + 3] = a[j];
+ }
}
- bi = (float*) (w->wavelet + 1 - w->cas);
+ bi = (float*)(w->wavelet + 1 - w->cas);
a += w->sn;
size -= w->sn;
count = w->dn;
}
}
-static void v4dwt_interleave_v(v4dwt_t* restrict v , float* restrict a , int x){
- v4* restrict bi = v->wavelet + v->cas;
+static void v4dwt_interleave_v(v4dwt_t* OPJ_RESTRICT v , float* OPJ_RESTRICT a , int x){
+ v4* OPJ_RESTRICT bi = v->wavelet + v->cas;
int i;
for(i = 0; i < v->sn; ++i){
memcpy(&bi[i*2], &a[i*x], 4 * sizeof(float));
@@ -621,7 +627,7 @@ static void v4dwt_interleave_v(v4dwt_t* restrict v , float* restrict a , int x){
#ifdef __SSE__
static void v4dwt_decode_step1_sse(v4* w, int count, const __m128 c){
- __m128* restrict vw = (__m128*) w;
+ __m128* OPJ_RESTRICT vw = (__m128*) w;
int i;
/* 4x unrolled loop */
for(i = 0; i < count >> 2; ++i){
@@ -642,22 +648,39 @@ static void v4dwt_decode_step1_sse(v4* w, int count, const __m128 c){
}
static void v4dwt_decode_step2_sse(v4* l, v4* w, int k, int m, __m128 c){
- __m128* restrict vl = (__m128*) l;
- __m128* restrict vw = (__m128*) w;
+ __m128* OPJ_RESTRICT vl = (__m128*) l;
+ __m128* OPJ_RESTRICT vw = (__m128*) w;
int i;
__m128 tmp1, tmp2, tmp3;
tmp1 = vl[0];
- for(i = 0; i < m; ++i){
+ for (i = 0; i < m - 3; i += 4) {
+ __m128 tmp4, tmp5, tmp6, tmp7, tmp8, tmp9;
+ tmp2 = vw[-1];
+ tmp3 = vw[0];
+ tmp4 = vw[1];
+ tmp5 = vw[2];
+ tmp6 = vw[3];
+ tmp7 = vw[4];
+ tmp8 = vw[5];
+ tmp9 = vw[6];
+ vw[-1] = _mm_add_ps(tmp2, _mm_mul_ps(_mm_add_ps(tmp1, tmp3), c));
+ vw[1] = _mm_add_ps(tmp4, _mm_mul_ps(_mm_add_ps(tmp3, tmp5), c));
+ vw[3] = _mm_add_ps(tmp6, _mm_mul_ps(_mm_add_ps(tmp5, tmp7), c));
+ vw[5] = _mm_add_ps(tmp8, _mm_mul_ps(_mm_add_ps(tmp7, tmp9), c));
+ tmp1 = tmp9;
+ vw += 8;
+ }
+ for ( ; i < m; ++i) {
tmp2 = vw[-1];
tmp3 = vw[ 0];
vw[-1] = _mm_add_ps(tmp2, _mm_mul_ps(_mm_add_ps(tmp1, tmp3), c));
tmp1 = tmp3;
vw += 2;
}
- vl = vw - 2;
if(m >= k){
return;
}
+ vl = vw - 2;
c = _mm_add_ps(c, c);
c = _mm_mul_ps(c, vl[0]);
for(; m < k; ++m){
@@ -670,7 +693,7 @@ static void v4dwt_decode_step2_sse(v4* l, v4* w, int k, int m, __m128 c){
#else
static void v4dwt_decode_step1(v4* w, int count, const float c){
- float* restrict fw = (float*) w;
+ float* OPJ_RESTRICT fw = (float*) w;
int i;
for(i = 0; i < count; ++i){
float tmp1 = fw[i*8 ];
@@ -685,8 +708,8 @@ static void v4dwt_decode_step1(v4* w, int count, const float c){
}
static void v4dwt_decode_step2(v4* l, v4* w, int k, int m, float c){
- float* restrict fl = (float*) l;
- float* restrict fw = (float*) w;
+ float* OPJ_RESTRICT fl = (float*) l;
+ float* OPJ_RESTRICT fw = (float*) w;
int i;
for(i = 0; i < m; ++i){
float tmp1_1 = fl[0];
@@ -737,42 +760,44 @@ static void v4dwt_decode_step2(v4* l, v4* w, int k, int m, float c){
/* */
/* Inverse 9-7 wavelet transform in 1-D. */
/* */
-static void v4dwt_decode(v4dwt_t* restrict dwt){
+static void v4dwt_decode(v4dwt_t* OPJ_RESTRICT dwt){
int a, b;
if(dwt->cas == 0) {
- if(!((dwt->dn > 0) || (dwt->sn > 1))){
+ if (dwt->dn <= 0 && dwt->sn <= 1) {
return;
}
a = 0;
b = 1;
}else{
- if(!((dwt->sn > 0) || (dwt->dn > 1))) {
+ if (dwt->sn <= 0 && dwt->dn <= 1) {
return;
}
a = 1;
b = 0;
}
+ v4* OPJ_RESTRICT waveleta = dwt->wavelet + a;
+ v4* OPJ_RESTRICT waveletb = dwt->wavelet + b;
#ifdef __SSE__
- v4dwt_decode_step1_sse(dwt->wavelet+a, dwt->sn, _mm_set1_ps(K));
- v4dwt_decode_step1_sse(dwt->wavelet+b, dwt->dn, _mm_set1_ps(c13318));
- v4dwt_decode_step2_sse(dwt->wavelet+b, dwt->wavelet+a+1, dwt->sn, int_min(dwt->sn, dwt->dn-a), _mm_set1_ps(dwt_delta));
- v4dwt_decode_step2_sse(dwt->wavelet+a, dwt->wavelet+b+1, dwt->dn, int_min(dwt->dn, dwt->sn-b), _mm_set1_ps(dwt_gamma));
- v4dwt_decode_step2_sse(dwt->wavelet+b, dwt->wavelet+a+1, dwt->sn, int_min(dwt->sn, dwt->dn-a), _mm_set1_ps(dwt_beta));
- v4dwt_decode_step2_sse(dwt->wavelet+a, dwt->wavelet+b+1, dwt->dn, int_min(dwt->dn, dwt->sn-b), _mm_set1_ps(dwt_alpha));
+ v4dwt_decode_step1_sse(waveleta, dwt->sn, _mm_set1_ps(K));
+ v4dwt_decode_step1_sse(waveletb, dwt->dn, _mm_set1_ps(c13318));
+ v4dwt_decode_step2_sse(waveletb, waveleta + 1, dwt->sn, int_min(dwt->sn, dwt->dn-a), _mm_set1_ps(dwt_delta));
+ v4dwt_decode_step2_sse(waveleta, waveletb + 1, dwt->dn, int_min(dwt->dn, dwt->sn-b), _mm_set1_ps(dwt_gamma));
+ v4dwt_decode_step2_sse(waveletb, waveleta + 1, dwt->sn, int_min(dwt->sn, dwt->dn-a), _mm_set1_ps(dwt_beta));
+ v4dwt_decode_step2_sse(waveleta, waveletb + 1, dwt->dn, int_min(dwt->dn, dwt->sn-b), _mm_set1_ps(dwt_alpha));
#else
- v4dwt_decode_step1(dwt->wavelet+a, dwt->sn, K);
- v4dwt_decode_step1(dwt->wavelet+b, dwt->dn, c13318);
- v4dwt_decode_step2(dwt->wavelet+b, dwt->wavelet+a+1, dwt->sn, int_min(dwt->sn, dwt->dn-a), dwt_delta);
- v4dwt_decode_step2(dwt->wavelet+a, dwt->wavelet+b+1, dwt->dn, int_min(dwt->dn, dwt->sn-b), dwt_gamma);
- v4dwt_decode_step2(dwt->wavelet+b, dwt->wavelet+a+1, dwt->sn, int_min(dwt->sn, dwt->dn-a), dwt_beta);
- v4dwt_decode_step2(dwt->wavelet+a, dwt->wavelet+b+1, dwt->dn, int_min(dwt->dn, dwt->sn-b), dwt_alpha);
+ v4dwt_decode_step1(waveleta, dwt->sn, K);
+ v4dwt_decode_step1(waveletb, dwt->dn, c13318);
+ v4dwt_decode_step2(waveletb, waveleta + 1, dwt->sn, int_min(dwt->sn, dwt->dn-a), dwt_delta);
+ v4dwt_decode_step2(waveleta, waveletb + 1, dwt->dn, int_min(dwt->dn, dwt->sn-b), dwt_gamma);
+ v4dwt_decode_step2(waveletb, waveleta + 1, dwt->sn, int_min(dwt->sn, dwt->dn-a), dwt_beta);
+ v4dwt_decode_step2(waveleta, waveletb + 1, dwt->dn, int_min(dwt->dn, dwt->sn-b), dwt_alpha);
#endif
}
/* */
/* Inverse 9-7 wavelet transform in 2-D. */
/* */
-void dwt_decode_real(opj_tcd_tilecomp_t* restrict tilec, int numres){
+void dwt_decode_real(opj_tcd_tilecomp_t* OPJ_RESTRICT tilec, int numres){
v4dwt_t h;
v4dwt_t v;
@@ -787,7 +812,7 @@ void dwt_decode_real(opj_tcd_tilecomp_t* restrict tilec, int numres){
v.wavelet = h.wavelet;
while( --numres) {
- float * restrict aj = (float*) tilec->data;
+ float * OPJ_RESTRICT aj = (float*) tilec->data;
int bufsize = (tilec->x1 - tilec->x0) * (tilec->y1 - tilec->y0);
int j;
diff --git a/indra/libopenjpeg/mct.c b/indra/libopenjpeg/mct.c
index 870993b06d..d55a67062e 100644
--- a/indra/libopenjpeg/mct.c
+++ b/indra/libopenjpeg/mct.c
@@ -29,11 +29,16 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+#define OPJ_SKIP_POISON
+#include "opj_includes.h"
+
#ifdef __SSE__
#include
#endif
-#include "opj_includes.h"
+#if defined(__GNUC__)
+#pragma GCC poison malloc calloc realloc free
+#endif
/* */
/* This table contains the norms of the basis function of the reversible MCT. */
@@ -49,17 +54,38 @@ static const double mct_norms_real[3] = { 1.732, 1.805, 1.573 };
/* Foward reversible MCT. */
/* */
void mct_encode(
- int* restrict c0,
- int* restrict c1,
- int* restrict c2,
+ int* OPJ_RESTRICT c0,
+ int* OPJ_RESTRICT c1,
+ int* OPJ_RESTRICT c2,
int n)
{
- int i;
- for(i = 0; i < n; ++i) {
+ int i = 0;
+#ifdef __SSE2__
+ /* Buffers are normally aligned on 16 bytes... */
+ if (((size_t)c0 & 0xf) == 0 && ((size_t)c1 & 0xf) == 0 && ((size_t)c2 & 0xf) == 0) {
+ const int cnt = n & ~3U;
+ for (; i < cnt; i += 4) {
+ __m128i y, u, v;
+ __m128i r = _mm_load_si128((const __m128i*) & (c0[i]));
+ __m128i g = _mm_load_si128((const __m128i*) & (c1[i]));
+ __m128i b = _mm_load_si128((const __m128i*) & (c2[i]));
+ y = _mm_add_epi32(g, g);
+ y = _mm_add_epi32(y, b);
+ y = _mm_add_epi32(y, r);
+ y = _mm_srai_epi32(y, 2);
+ u = _mm_sub_epi32(b, g);
+ v = _mm_sub_epi32(r, g);
+ _mm_store_si128((__m128i*) & (c0[i]), y);
+ _mm_store_si128((__m128i*) & (c1[i]), u);
+ _mm_store_si128((__m128i*) & (c2[i]), v);
+ }
+ }
+#endif
+ for (; i < n; ++i) {
int r = c0[i];
int g = c1[i];
int b = c2[i];
- int y = (r + (g * 2) + b) >> 2;
+ int y = (r + g + g + b) >> 2;
int u = b - g;
int v = r - g;
c0[i] = y;
@@ -72,13 +98,32 @@ void mct_encode(
/* Inverse reversible MCT. */
/* */
void mct_decode(
- int* restrict c0,
- int* restrict c1,
- int* restrict c2,
+ int* OPJ_RESTRICT c0,
+ int* OPJ_RESTRICT c1,
+ int* OPJ_RESTRICT c2,
int n)
{
- int i;
- for (i = 0; i < n; ++i) {
+ int i = 0;
+#ifdef __SSE2__
+ /* Buffers are normally aligned on 16 bytes... */
+ if (((size_t)c0 & 0xf) == 0 && ((size_t)c1 & 0xf) == 0 && ((size_t)c2 & 0xf) == 0) {
+ const int cnt = n & ~3U;
+ for (; i < cnt; i += 4) {
+ __m128i r, g, b;
+ __m128i y = _mm_load_si128((const __m128i*) & (c0[i]));
+ __m128i u = _mm_load_si128((const __m128i*) & (c1[i]));
+ __m128i v = _mm_load_si128((const __m128i*) & (c2[i]));
+ g = y;
+ g = _mm_sub_epi32(g, _mm_srai_epi32(_mm_add_epi32(u, v), 2));
+ r = _mm_add_epi32(v, g);
+ b = _mm_add_epi32(u, g);
+ _mm_store_si128((__m128i*) & (c0[i]), r);
+ _mm_store_si128((__m128i*) & (c1[i]), g);
+ _mm_store_si128((__m128i*) & (c2[i]), b);
+}
+ }
+#endif
+ for (; i < n; ++i) {
int y = c0[i];
int u = c1[i];
int v = c2[i];
@@ -102,13 +147,119 @@ double mct_getnorm(int compno) {
/* Foward irreversible MCT. */
/* */
void mct_encode_real(
- int* restrict c0,
- int* restrict c1,
- int* restrict c2,
+ int* OPJ_RESTRICT c0,
+ int* OPJ_RESTRICT c1,
+ int* OPJ_RESTRICT c2,
int n)
{
- int i;
- for(i = 0; i < n; ++i) {
+ int i = 0;
+#ifdef __SSE4_1__
+ /* Buffers are normally aligned on 16 bytes... */
+ if (((size_t)c0 & 0xf) == 0 && ((size_t)c1 & 0xf) == 0 && ((size_t)c2 & 0xf) == 0) {
+ const int cnt = n & ~3U;
+ const __m128i ry = _mm_set1_epi32(2449);
+ const __m128i gy = _mm_set1_epi32(4809);
+ const __m128i by = _mm_set1_epi32(934);
+ const __m128i ru = _mm_set1_epi32(1382);
+ const __m128i gu = _mm_set1_epi32(2714);
+ const __m128i gv = _mm_set1_epi32(3430);
+ const __m128i bv = _mm_set1_epi32(666);
+ const __m128i mulround = _mm_shuffle_epi32(_mm_cvtsi32_si128(4096), _MM_SHUFFLE(1, 0, 1, 0));
+ for (; i < cnt; i += 4) {
+ __m128i lo, hi, y, u, v;
+ __m128i r = _mm_load_si128((const __m128i*) & (c0[i]));
+ __m128i g = _mm_load_si128((const __m128i*) & (c1[i]));
+ __m128i b = _mm_load_si128((const __m128i*) & (c2[i]));
+
+ hi = _mm_shuffle_epi32(r, _MM_SHUFFLE(3, 3, 1, 1));
+ lo = _mm_mul_epi32(r, ry);
+ hi = _mm_mul_epi32(hi, ry);
+ lo = _mm_add_epi64(lo, mulround);
+ hi = _mm_add_epi64(hi, mulround);
+ lo = _mm_srli_epi64(lo, 13);
+ hi = _mm_slli_epi64(hi, 32 - 13);
+ y = _mm_blend_epi16(lo, hi, 0xCC);
+
+ hi = _mm_shuffle_epi32(g, _MM_SHUFFLE(3, 3, 1, 1));
+ lo = _mm_mul_epi32(g, gy);
+ hi = _mm_mul_epi32(hi, gy);
+ lo = _mm_add_epi64(lo, mulround);
+ hi = _mm_add_epi64(hi, mulround);
+ lo = _mm_srli_epi64(lo, 13);
+ hi = _mm_slli_epi64(hi, 32 - 13);
+ y = _mm_add_epi32(y, _mm_blend_epi16(lo, hi, 0xCC));
+
+ hi = _mm_shuffle_epi32(b, _MM_SHUFFLE(3, 3, 1, 1));
+ lo = _mm_mul_epi32(b, by);
+ hi = _mm_mul_epi32(hi, by);
+ lo = _mm_add_epi64(lo, mulround);
+ hi = _mm_add_epi64(hi, mulround);
+ lo = _mm_srli_epi64(lo, 13);
+ hi = _mm_slli_epi64(hi, 32 - 13);
+ y = _mm_add_epi32(y, _mm_blend_epi16(lo, hi, 0xCC));
+ _mm_store_si128((__m128i*) & (c0[i]), y);
+
+ lo = _mm_cvtepi32_epi64(_mm_shuffle_epi32(b, _MM_SHUFFLE(3, 2, 2, 0)));
+ hi = _mm_cvtepi32_epi64(_mm_shuffle_epi32(b, _MM_SHUFFLE(3, 2, 3, 1)));
+ lo = _mm_slli_epi64(lo, 12);
+ hi = _mm_slli_epi64(hi, 12);
+ lo = _mm_add_epi64(lo, mulround);
+ hi = _mm_add_epi64(hi, mulround);
+ lo = _mm_srli_epi64(lo, 13);
+ hi = _mm_slli_epi64(hi, 32 - 13);
+ u = _mm_blend_epi16(lo, hi, 0xCC);
+
+ hi = _mm_shuffle_epi32(r, _MM_SHUFFLE(3, 3, 1, 1));
+ lo = _mm_mul_epi32(r, ru);
+ hi = _mm_mul_epi32(hi, ru);
+ lo = _mm_add_epi64(lo, mulround);
+ hi = _mm_add_epi64(hi, mulround);
+ lo = _mm_srli_epi64(lo, 13);
+ hi = _mm_slli_epi64(hi, 32 - 13);
+ u = _mm_sub_epi32(u, _mm_blend_epi16(lo, hi, 0xCC));
+
+ hi = _mm_shuffle_epi32(g, _MM_SHUFFLE(3, 3, 1, 1));
+ lo = _mm_mul_epi32(g, gu);
+ hi = _mm_mul_epi32(hi, gu);
+ lo = _mm_add_epi64(lo, mulround);
+ hi = _mm_add_epi64(hi, mulround);
+ lo = _mm_srli_epi64(lo, 13);
+ hi = _mm_slli_epi64(hi, 32 - 13);
+ u = _mm_sub_epi32(u, _mm_blend_epi16(lo, hi, 0xCC));
+ _mm_store_si128((__m128i*) & (c1[i]), u);
+
+ lo = _mm_cvtepi32_epi64(_mm_shuffle_epi32(r, _MM_SHUFFLE(3, 2, 2, 0)));
+ hi = _mm_cvtepi32_epi64(_mm_shuffle_epi32(r, _MM_SHUFFLE(3, 2, 3, 1)));
+ lo = _mm_slli_epi64(lo, 12);
+ hi = _mm_slli_epi64(hi, 12);
+ lo = _mm_add_epi64(lo, mulround);
+ hi = _mm_add_epi64(hi, mulround);
+ lo = _mm_srli_epi64(lo, 13);
+ hi = _mm_slli_epi64(hi, 32 - 13);
+ v = _mm_blend_epi16(lo, hi, 0xCC);
+
+ hi = _mm_shuffle_epi32(g, _MM_SHUFFLE(3, 3, 1, 1));
+ lo = _mm_mul_epi32(g, gv);
+ hi = _mm_mul_epi32(hi, gv);
+ lo = _mm_add_epi64(lo, mulround);
+ hi = _mm_add_epi64(hi, mulround);
+ lo = _mm_srli_epi64(lo, 13);
+ hi = _mm_slli_epi64(hi, 32 - 13);
+ v = _mm_sub_epi32(v, _mm_blend_epi16(lo, hi, 0xCC));
+
+ hi = _mm_shuffle_epi32(b, _MM_SHUFFLE(3, 3, 1, 1));
+ lo = _mm_mul_epi32(b, bv);
+ hi = _mm_mul_epi32(hi, bv);
+ lo = _mm_add_epi64(lo, mulround);
+ hi = _mm_add_epi64(hi, mulround);
+ lo = _mm_srli_epi64(lo, 13);
+ hi = _mm_slli_epi64(hi, 32 - 13);
+ v = _mm_sub_epi32(v, _mm_blend_epi16(lo, hi, 0xCC));
+ _mm_store_si128((__m128i*) & (c2[i]), v);
+ }
+ }
+#endif
+ for (; i < n; ++i) {
int r = c0[i];
int g = c1[i];
int b = c2[i];
@@ -125,19 +276,21 @@ void mct_encode_real(
/* Inverse irreversible MCT. */
/* */
void mct_decode_real(
- float* restrict c0,
- float* restrict c1,
- float* restrict c2,
+ float* OPJ_RESTRICT c0,
+ float* OPJ_RESTRICT c1,
+ float* OPJ_RESTRICT c2,
int n)
{
int i;
#ifdef __SSE__
+ int count;
__m128 vrv, vgu, vgv, vbu;
vrv = _mm_set1_ps(1.402f);
vgu = _mm_set1_ps(0.34413f);
vgv = _mm_set1_ps(0.71414f);
vbu = _mm_set1_ps(1.772f);
- for (i = 0; i < (n >> 3); ++i) {
+ count = n >> 3;
+ for (i = 0; i < count; ++i) {
__m128 vy, vu, vv;
__m128 vr, vg, vb;
@@ -174,7 +327,7 @@ void mct_decode_real(
float u = c1[i];
float v = c2[i];
float r = y + (v * 1.402f);
- float g = y - (u * 0.34413f) - (v * (0.71414f));
+ float g = y - (u * 0.34413f) - (v * 0.71414f);
float b = y + (u * 1.772f);
c0[i] = r;
c1[i] = g;
diff --git a/indra/libopenjpeg/openjpeg.h b/indra/libopenjpeg/openjpeg.h
index 59147c8b3d..ba88114154 100644
--- a/indra/libopenjpeg/openjpeg.h
+++ b/indra/libopenjpeg/openjpeg.h
@@ -40,33 +40,71 @@
==========================================================
*/
+/*
+The inline keyword is supported by C99 but not by C90.
+Most compilers implement their own version of this keyword ...
+*/
+#ifndef INLINE
+#if defined(_MSC_VER)
+#define INLINE __forceinline
+#elif defined(__GNUC__)
+#define INLINE __inline__
+#elif defined(__MWERKS__)
+#define INLINE inline
+#else
+/* add other compilers here ... */
+#define INLINE
+#endif /* defined() */
+#endif /* INLINE */
#if defined(OPJ_STATIC) || !defined(_WIN32)
#define OPJ_API
#define OPJ_CALLCONV
#else
#define OPJ_CALLCONV __stdcall
/*
-The following ifdef block is the standard way of creating macros which make exporting
+The following ifdef block is the standard way of creating macros which make exporting
from a DLL simpler. All files within this DLL are compiled with the OPJ_EXPORTS
symbol defined on the command line. this symbol should not be defined on any project
-that uses this DLL. This way any other project whose source files include this file see
-OPJ_API functions as being imported from a DLL, wheras this DLL sees symbols
+that uses this DLL. This way any other project whose source files include this file see
+OPJ_API functions as being imported from a DLL, whereas this DLL sees symbols
defined with this macro as being exported.
*/
-#if defined(OPJ_EXPORTS) || defined(DLL_EXPORT)
-#define OPJ_API __declspec(dllexport)
-#else
-#define OPJ_API __declspec(dllimport)
-#endif /* OPJ_EXPORTS */
+# if defined(OPJ_EXPORTS) || defined(DLL_EXPORT)
+# define OPJ_API __declspec(dllexport)
+# else
+# define OPJ_API __declspec(dllimport)
+# endif /* OPJ_EXPORTS */
#endif /* !OPJ_STATIC || !_WIN32 */
typedef int opj_bool;
#define OPJ_TRUE 1
#define OPJ_FALSE 0
+typedef char OPJ_CHAR;
+typedef float OPJ_FLOAT32;
+typedef double OPJ_FLOAT64;
+typedef unsigned char OPJ_BYTE;
+
+#include "opj_stdint.h"
+
+typedef int8_t OPJ_INT8;
+typedef uint8_t OPJ_UINT8;
+typedef int16_t OPJ_INT16;
+typedef uint16_t OPJ_UINT16;
+typedef int32_t OPJ_INT32;
+typedef uint32_t OPJ_UINT32;
+typedef int64_t OPJ_INT64;
+typedef uint64_t OPJ_UINT64;
+
+typedef int64_t OPJ_OFF_T; /* 64-bit file offset type */
+
+#include
+typedef size_t OPJ_SIZE_T;
+
/* Avoid compile-time warning because parameter is not used */
#define OPJ_ARG_NOT_USED(x) (void)(x)
-/*
+
+/*
==========================================================
Useful constant definitions
==========================================================
diff --git a/indra/libopenjpeg/opj_includes.h b/indra/libopenjpeg/opj_includes.h
index 2b5866a999..e4d2374da0 100644
--- a/indra/libopenjpeg/opj_includes.h
+++ b/indra/libopenjpeg/opj_includes.h
@@ -40,6 +40,8 @@
#include
#include
#include
+#include
+#include
/*
==========================================================
@@ -54,56 +56,115 @@
==========================================================
*/
+/* Are restricted pointers available? (C99) */
+#if (__STDC_VERSION__ >= 199901L)
+#define OPJ_RESTRICT restrict
+#else
+/* Not a C99 compiler */
+#if defined(__GNUC__)
+#define OPJ_RESTRICT __restrict__
+#elif defined(_MSC_VER) && (_MSC_VER >= 1400)
+#define OPJ_RESTRICT __restrict
+#else
+#define OPJ_RESTRICT /* restrict */
+#endif
+#endif
+
/* Ignore GCC attributes if this is not GCC */
#ifndef __GNUC__
#define __attribute__(x) /* __attribute__(x) */
#endif
-/*
-The inline keyword is supported by C99 but not by C90.
-Most compilers implement their own version of this keyword ...
-*/
-#ifndef INLINE
- #if defined(_MSC_VER)
- #define INLINE __forceinline
- #elif defined(__GNUC__)
- #define INLINE __inline__
- #elif defined(__MWERKS__)
- #define INLINE inline
- #else
- /* add other compilers here ... */
- #define INLINE
- #endif /* defined() */
-#endif /* INLINE */
-/* Are restricted pointers available? (C99) */
-#if (__STDC_VERSION__ != 199901L)
- /* Not a C99 compiler */
- #ifdef __GNUC__
- #define restrict __restrict__
- #else
- #define restrict /* restrict */
- #endif
-#endif
+/* MSVC before 2013 and Borland C do not have lrintf */
+#if defined(_MSC_VER)
+#include
+static INLINE long opj_lrintf(float f)
+{
+#ifdef _M_X64
+ return _mm_cvt_ss2si(_mm_load_ss(&f));
-/* MSVC and Borland C do not have lrintf */
-#if defined(_MSC_VER) || defined(__BORLANDC__)
-static INLINE long lrintf(float f){
+ /* commented out line breaks many tests */
+ /* return (long)((f>0.0f) ? (f + 0.5f):(f -0.5f)); */
+#elif defined(_M_IX86)
+ int i;
+ _asm{
+ fld f
+ fistp i
+ };
+
+ return i;
+#else
+ return (long)((f>0.0f) ? (f + 0.5f) : (f - 0.5f));
+#endif
+}
+#elif defined(__BORLANDC__)
+static INLINE long opj_lrintf(float f)
+{
#ifdef _M_X64
- return (long)((f>0.0f) ? (f + 0.5f):(f -0.5f));
+ return (long)((f > 0.0f) ? (f + 0.5f) : (f - 0.5f));
#else
int i;
-
- _asm{
+
+ _asm {
fld f
fistp i
};
-
+
return i;
#endif
}
+#else
+static INLINE long opj_lrintf(float f)
+{
+ return lrintf(f);
+}
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER < 1400)
+#define vsnprintf _vsnprintf
+#endif
+
+/* MSVC x86 is really bad at doing int64 = int32 * int32 on its own. Use intrinsic. */
+#if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(__INTEL_COMPILER) && defined(_M_IX86)
+# include
+# pragma intrinsic(__emul)
+#endif
+
+/* Apparently Visual Studio doesn't define __SSE__ / __SSE2__ macros */
+#if defined(_M_X64)
+/* Intel 64bit support SSE and SSE2 */
+# ifndef __SSE__
+# define __SSE__ 1
+# endif
+# ifndef __SSE2__
+# define __SSE2__ 1
+# endif
+# if !defined(__SSE4_1__) && defined(__AVX__)
+# define __SSE4_1__ 1
+# endif
#endif
+/* For x86, test the value of the _M_IX86_FP macro. */
+/* See https://msdn.microsoft.com/en-us/library/b0084kay.aspx */
+#if defined(_M_IX86_FP)
+# if _M_IX86_FP >= 1
+# ifndef __SSE__
+# define __SSE__ 1
+# endif
+# endif
+# if _M_IX86_FP >= 2
+# ifndef __SSE2__
+# define __SSE2__ 1
+# endif
+# endif
+#endif
+
+/* Type to use for bit-fields in internal headers */
+typedef unsigned int OPJ_BITFIELD;
+
+#define OPJ_UNUSED(x) (void)x
+
#include "j2k_lib.h"
#include "opj_malloc.h"
#include "event.h"
diff --git a/indra/libopenjpeg/opj_malloc.c b/indra/libopenjpeg/opj_malloc.c
new file mode 100644
index 0000000000..dca91bfcbe
--- /dev/null
+++ b/indra/libopenjpeg/opj_malloc.c
@@ -0,0 +1,249 @@
+/*
+ * The copyright in this software is being made available under the 2-clauses
+ * BSD License, included below. This software may be subject to other third
+ * party and contributor rights, including patent rights, and no such rights
+ * are granted under this license.
+ *
+ * Copyright (c) 2015, Mathieu Malaterre
+ * Copyright (c) 2015, Matthieu Darbois
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#define OPJ_SKIP_POISON
+#include "opj_includes.h"
+
+#if defined(OPJ_HAVE_MALLOC_H) && defined(OPJ_HAVE_MEMALIGN)
+# include
+#endif
+
+#ifndef SIZE_MAX
+# define SIZE_MAX ((size_t) -1)
+#endif
+
+static INLINE void *opj_aligned_alloc_n(size_t alignment, size_t size)
+{
+ void* ptr;
+
+ /* alignment shall be power of 2 */
+ assert((alignment != 0U) && ((alignment & (alignment - 1U)) == 0U));
+ /* alignment shall be at least sizeof(void*) */
+ assert(alignment >= sizeof(void*));
+
+ if (size == 0U) { /* prevent implementation defined behavior of realloc */
+ return NULL;
+ }
+
+#if defined(OPJ_HAVE_POSIX_MEMALIGN)
+ /* aligned_alloc requires c11, restrict to posix_memalign for now. Quote:
+ * This function was introduced in POSIX 1003.1d. Although this function is
+ * superseded by aligned_alloc, it is more portable to older POSIX systems
+ * that do not support ISO C11. */
+ if (posix_memalign(&ptr, alignment, size)) {
+ ptr = NULL;
+ }
+ /* older linux */
+#elif defined(OPJ_HAVE_MEMALIGN)
+ ptr = memalign(alignment, size);
+ /* _MSC_VER */
+#elif defined(OPJ_HAVE__ALIGNED_MALLOC)
+ ptr = _aligned_malloc(size, alignment);
+#else
+ /*
+ * Generic aligned malloc implementation.
+ * Uses size_t offset for the integer manipulation of the pointer,
+ * as uintptr_t is not available in C89 to do
+ * bitwise operations on the pointer itself.
+ */
+ alignment--;
+ {
+ size_t offset;
+ OPJ_UINT8 *mem;
+
+ /* Room for padding and extra pointer stored in front of allocated area */
+ size_t overhead = alignment + sizeof(void *);
+
+ /* let's be extra careful */
+ assert(alignment <= (SIZE_MAX - sizeof(void *)));
+
+ /* Avoid integer overflow */
+ if (size > (SIZE_MAX - overhead)) {
+ return NULL;
+ }
+
+ mem = (OPJ_UINT8*)malloc(size + overhead);
+ if (mem == NULL) {
+ return mem;
+ }
+ /* offset = ((alignment + 1U) - ((size_t)(mem + sizeof(void*)) & alignment)) & alignment; */
+ /* Use the fact that alignment + 1U is a power of 2 */
+ offset = ((alignment ^ ((size_t)(mem + sizeof(void*)) & alignment)) + 1U) &
+ alignment;
+ ptr = (void *)(mem + sizeof(void*) + offset);
+ ((void**) ptr)[-1] = mem;
+ }
+#endif
+ return ptr;
+}
+static INLINE void *opj_aligned_realloc_n(void *ptr, size_t alignment,
+ size_t new_size)
+{
+ void *r_ptr;
+
+ /* alignment shall be power of 2 */
+ assert((alignment != 0U) && ((alignment & (alignment - 1U)) == 0U));
+ /* alignment shall be at least sizeof(void*) */
+ assert(alignment >= sizeof(void*));
+
+ if (new_size == 0U) { /* prevent implementation defined behavior of realloc */
+ return NULL;
+ }
+
+ /* no portable aligned realloc */
+#if defined(OPJ_HAVE_POSIX_MEMALIGN) || defined(OPJ_HAVE_MEMALIGN)
+ /* glibc doc states one can mix aligned malloc with realloc */
+ r_ptr = realloc(ptr, new_size); /* fast path */
+ /* we simply use `size_t` to cast, since we are only interest in binary AND
+ * operator */
+ if (((size_t)r_ptr & (alignment - 1U)) != 0U) {
+ /* this is non-trivial to implement a portable aligned realloc, so use a
+ * simple approach where we do not need a function that return the size of an
+ * allocated array (eg. _msize on Windows, malloc_size on MacOS,
+ * malloc_usable_size on systems with glibc) */
+ void *a_ptr = opj_aligned_alloc_n(alignment, new_size);
+ if (a_ptr != NULL) {
+ memcpy(a_ptr, r_ptr, new_size);
+ }
+ free(r_ptr);
+ r_ptr = a_ptr;
+ }
+ /* _MSC_VER */
+#elif defined(OPJ_HAVE__ALIGNED_MALLOC)
+ r_ptr = _aligned_realloc(ptr, new_size, alignment);
+#else
+ if (ptr == NULL) {
+ return opj_aligned_alloc_n(alignment, new_size);
+ }
+ alignment--;
+ {
+ void *oldmem;
+ OPJ_UINT8 *newmem;
+ size_t overhead = alignment + sizeof(void *);
+
+ /* let's be extra careful */
+ assert(alignment <= (SIZE_MAX - sizeof(void *)));
+
+ /* Avoid integer overflow */
+ if (new_size > SIZE_MAX - overhead) {
+ return NULL;
+ }
+
+ oldmem = ((void**) ptr)[-1];
+ newmem = (OPJ_UINT8*)realloc(oldmem, new_size + overhead);
+ if (newmem == NULL) {
+ return newmem;
+ }
+
+ if (newmem == oldmem) {
+ r_ptr = ptr;
+ } else {
+ size_t old_offset;
+ size_t new_offset;
+
+ /* realloc created a new copy, realign the copied memory block */
+ old_offset = (size_t)((OPJ_UINT8*)ptr - (OPJ_UINT8*)oldmem);
+
+ /* offset = ((alignment + 1U) - ((size_t)(mem + sizeof(void*)) & alignment)) & alignment; */
+ /* Use the fact that alignment + 1U is a power of 2 */
+ new_offset = ((alignment ^ ((size_t)(newmem + sizeof(void*)) & alignment)) +
+ 1U) & alignment;
+ new_offset += sizeof(void*);
+ r_ptr = (void *)(newmem + new_offset);
+
+ if (new_offset != old_offset) {
+ memmove(newmem + new_offset, newmem + old_offset, new_size);
+ }
+ ((void**) r_ptr)[-1] = newmem;
+ }
+ }
+#endif
+ return r_ptr;
+}
+void * opj_malloc(size_t size)
+{
+ if (size == 0U) { /* prevent implementation defined behavior of realloc */
+ return NULL;
+ }
+ return malloc(size);
+}
+void * opj_calloc(size_t num, size_t size)
+{
+ if (num == 0 || size == 0) {
+ /* prevent implementation defined behavior of realloc */
+ return NULL;
+ }
+ return calloc(num, size);
+}
+
+void *opj_aligned_malloc(size_t size)
+{
+ return opj_aligned_alloc_n(16U, size);
+}
+void * opj_aligned_realloc(void *ptr, size_t size)
+{
+ return opj_aligned_realloc_n(ptr, 16U, size);
+}
+
+void *opj_aligned_32_malloc(size_t size)
+{
+ return opj_aligned_alloc_n(32U, size);
+}
+void * opj_aligned_32_realloc(void *ptr, size_t size)
+{
+ return opj_aligned_realloc_n(ptr, 32U, size);
+}
+
+void opj_aligned_free(void* ptr)
+{
+#if defined(OPJ_HAVE_POSIX_MEMALIGN) || defined(OPJ_HAVE_MEMALIGN)
+ free(ptr);
+#elif defined(OPJ_HAVE__ALIGNED_MALLOC)
+ _aligned_free(ptr);
+#else
+ /* Generic implementation has malloced pointer stored in front of used area */
+ if (ptr != NULL) {
+ free(((void**) ptr)[-1]);
+ }
+#endif
+}
+
+void * opj_realloc(void *ptr, size_t new_size)
+{
+ if (new_size == 0U) { /* prevent implementation defined behavior of realloc */
+ return NULL;
+ }
+ return realloc(ptr, new_size);
+}
+void opj_free(void *ptr)
+{
+ free(ptr);
+}
diff --git a/indra/libopenjpeg/opj_malloc.h b/indra/libopenjpeg/opj_malloc.h
index aef2ee3b8c..4eacfa152d 100644
--- a/indra/libopenjpeg/opj_malloc.h
+++ b/indra/libopenjpeg/opj_malloc.h
@@ -1,4 +1,9 @@
/*
+ * The copyright in this software is being made available under the 2-clauses
+ * BSD License, included below. This software may be subject to other third
+ * party and contributor rights, including patent rights, and no such rights
+ * are granted under this license.
+ *
* Copyright (c) 2005, Herve Drolon, FreeImage Team
* Copyright (c) 2007, Callum Lerwick
* All rights reserved.
@@ -24,8 +29,10 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef __OPJ_MALLOC_H
-#define __OPJ_MALLOC_H
+#ifndef OPJ_MALLOC_H
+#define OPJ_MALLOC_H
+
+#include
/**
@file opj_malloc.h
@brief Internal functions
@@ -36,6 +43,17 @@ The functions in opj_malloc.h are internal utilities used for memory management.
/** @defgroup MISC MISC - Miscellaneous internal functions */
/*@{*/
+/* FIXME: These should be set with cmake tests, but we're currently not requiring use of cmake */
+#ifdef _WIN32
+#define OPJ_HAVE__ALIGNED_MALLOC
+#else /* Not _WIN32 */
+#if defined(__sun)
+#define OPJ_HAVE_MEMALIGN
+#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
+#define OPJ_HAVE_POSIX_MEMALIGN
+#endif
+#endif
+
/** @name Exported functions */
/*@{*/
/* ----------------------------------------------------------------------- */
@@ -45,90 +63,32 @@ Allocate an uninitialized memory block
@param size Bytes to allocate
@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available
*/
-#ifdef ALLOC_PERF_OPT
-void * OPJ_CALLCONV opj_malloc(size_t size);
-#else
-#define opj_malloc(size) malloc(size)
-#endif
+void * opj_malloc(size_t size);
/**
Allocate a memory block with elements initialized to 0
-@param num Blocks to allocate
-@param size Bytes per block to allocate
+@param numOfElements Blocks to allocate
+@param sizeOfElements Bytes per block to allocate
@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available
*/
-#ifdef ALLOC_PERF_OPT
-void * OPJ_CALLCONV opj_calloc(size_t _NumOfElements, size_t _SizeOfElements);
-#else
-#define opj_calloc(num, size) calloc(num, size)
-#endif
+void * opj_calloc(size_t numOfElements, size_t sizeOfElements);
/**
-Allocate memory aligned to a 16 byte boundry
+Allocate memory aligned to a 16 byte boundary
@param size Bytes to allocate
@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available
*/
-/* FIXME: These should be set with cmake tests, but we're currently not requiring use of cmake */
-#ifdef _WIN32
- /* Someone should tell the mingw people that their malloc.h ought to provide _mm_malloc() */
- #ifdef __GNUC__
- #include
- #define HAVE_MM_MALLOC
- #else /* MSVC, Intel C++ */
- #include
- #ifdef _mm_malloc
- #define HAVE_MM_MALLOC
- #endif
- #endif
-#else /* Not _WIN32 */
- #if defined(__sun)
- #define HAVE_MEMALIGN
- #elif defined(__FreeBSD__)
- #define HAVE_POSIX_MEMALIGN
- /* Linux x86_64 and OSX always align allocations to 16 bytes */
- #elif !defined(__amd64__) && !defined(__APPLE__) && !defined(_AIX)
- #define HAVE_MEMALIGN
- #include
- #endif
-#endif
+void * opj_aligned_malloc(size_t size);
+void * opj_aligned_realloc(void *ptr, size_t size);
+void opj_aligned_free(void* ptr);
-#define opj_aligned_malloc(size) malloc(size)
-#define opj_aligned_free(m) free(m)
-
-#ifdef HAVE_MM_MALLOC
- #undef opj_aligned_malloc
- #define opj_aligned_malloc(size) _mm_malloc(size, 16)
- #undef opj_aligned_free
- #define opj_aligned_free(m) _mm_free(m)
-#endif
-
-#ifdef HAVE_MEMALIGN
- extern void* memalign(size_t, size_t);
- #undef opj_aligned_malloc
- #define opj_aligned_malloc(size) memalign(16, (size))
- #undef opj_aligned_free
- #define opj_aligned_free(m) free(m)
-#endif
-
-#ifdef HAVE_POSIX_MEMALIGN
- #undef opj_aligned_malloc
- extern int posix_memalign(void**, size_t, size_t);
-
- static INLINE void* __attribute__ ((malloc)) opj_aligned_malloc(size_t size){
- void* mem = NULL;
- posix_memalign(&mem, 16, size);
- return mem;
- }
- #undef opj_aligned_free
- #define opj_aligned_free(m) free(m)
-#endif
-
-#ifdef ALLOC_PERF_OPT
- #undef opj_aligned_malloc
- #define opj_aligned_malloc(size) opj_malloc(size)
- #undef opj_aligned_free
- #define opj_aligned_free(m) opj_free(m)
-#endif
+/**
+Allocate memory aligned to a 32 byte boundary
+@param size Bytes to allocate
+@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available
+*/
+void * opj_aligned_32_malloc(size_t size);
+void * opj_aligned_32_realloc(void *ptr, size_t size);
/**
Reallocate memory blocks.
@@ -136,23 +96,15 @@ Reallocate memory blocks.
@param s New size in bytes
@return Returns a void pointer to the reallocated (and possibly moved) memory block
*/
-#ifdef ALLOC_PERF_OPT
-void * OPJ_CALLCONV opj_realloc(void * m, size_t s);
-#else
-#define opj_realloc(m, s) realloc(m, s)
-#endif
+void * opj_realloc(void * m, size_t s);
/**
Deallocates or frees a memory block.
@param m Previously allocated memory block to be freed
*/
-#ifdef ALLOC_PERF_OPT
-void OPJ_CALLCONV opj_free(void * m);
-#else
-#define opj_free(m) free(m)
-#endif
+void opj_free(void * m);
-#ifdef __GNUC__
+#if defined(__GNUC__) && !defined(OPJ_SKIP_POISON)
#pragma GCC poison malloc calloc realloc free
#endif
@@ -161,5 +113,5 @@ void OPJ_CALLCONV opj_free(void * m);
/*@}*/
-#endif /* __OPJ_MALLOC_H */
+#endif /* OPJ_MALLOC_H */
diff --git a/indra/libopenjpeg/opj_stdint.h b/indra/libopenjpeg/opj_stdint.h
new file mode 100644
index 0000000000..337ad85001
--- /dev/null
+++ b/indra/libopenjpeg/opj_stdint.h
@@ -0,0 +1,51 @@
+/*
+ * The copyright in this software is being made available under the 2-clauses
+ * BSD License, included below. This software may be subject to other third
+ * party and contributor rights, including patent rights, and no such rights
+ * are granted under this license.
+ *
+ * Copyright (c) 2012, Mathieu Malaterre
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef OPJ_STDINT_H
+#define OPJ_STDINT_H
+
+#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || _MSC_VER >= 1900
+#include
+#else
+#if defined(_WIN32)
+typedef signed __int8 int8_t;
+typedef unsigned __int8 uint8_t;
+typedef signed __int16 int16_t;
+typedef unsigned __int16 uint16_t;
+typedef signed __int32 int32_t;
+typedef unsigned __int32 uint32_t;
+typedef signed __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+#else
+#error unsupported platform
+#endif
+#endif
+
+#endif /* OPJ_STDINT_H */
diff --git a/indra/libopenjpeg/t1.c b/indra/libopenjpeg/t1.c
index 93b997b799..6cb8acad15 100644
--- a/indra/libopenjpeg/t1.c
+++ b/indra/libopenjpeg/t1.c
@@ -1427,7 +1427,7 @@ void t1_encode_cblks(
opj_tcd_resolution_t *res = &tilec->resolutions[resno];
for (bandno = 0; bandno < res->numbands; ++bandno) {
- opj_tcd_band_t* restrict band = &res->bands[bandno];
+ opj_tcd_band_t* OPJ_RESTRICT band = &res->bands[bandno];
int bandconst = 8192 * 8192 / ((int) floor(band->stepsize * 8192));
for (precno = 0; precno < res->pw * res->ph; ++precno) {
@@ -1435,8 +1435,8 @@ void t1_encode_cblks(
for (cblkno = 0; cblkno < prc->cw * prc->ch; ++cblkno) {
opj_tcd_cblk_enc_t* cblk = &prc->cblks.enc[cblkno];
- int* restrict datap;
- int* restrict tiledp;
+ int* OPJ_RESTRICT datap;
+ int* OPJ_RESTRICT tiledp;
int cblk_w;
int cblk_h;
int i, j;
@@ -1517,14 +1517,14 @@ void t1_decode_cblks(
opj_tcd_resolution_t* res = &tilec->resolutions[resno];
for (bandno = 0; bandno < res->numbands; ++bandno) {
- opj_tcd_band_t* restrict band = &res->bands[bandno];
+ opj_tcd_band_t* OPJ_RESTRICT band = &res->bands[bandno];
for (precno = 0; precno < res->pw * res->ph; ++precno) {
opj_tcd_precinct_t* precinct = &band->precincts[precno];
for (cblkno = 0; cblkno < precinct->cw * precinct->ch; ++cblkno) {
opj_tcd_cblk_dec_t* cblk = &precinct->cblks.dec[cblkno];
- int* restrict datap;
+ int* OPJ_RESTRICT datap;
int cblk_w, cblk_h;
int x, y;
int i, j;
@@ -1566,7 +1566,7 @@ void t1_decode_cblks(
}
if (tccp->qmfbid == 1) {
- int* restrict tiledp = &tilec->data[(y * tile_w) + x];
+ int* OPJ_RESTRICT tiledp = &tilec->data[(y * tile_w) + x];
for (j = 0; j < cblk_h; ++j) {
for (i = 0; i < cblk_w; ++i) {
int tmp = datap[(j * cblk_w) + i];
@@ -1574,9 +1574,9 @@ void t1_decode_cblks(
}
}
} else { /* if (tccp->qmfbid == 0) */
- float* restrict tiledp = (float*) &tilec->data[(y * tile_w) + x];
+ float* OPJ_RESTRICT tiledp = (float*) &tilec->data[(y * tile_w) + x];
for (j = 0; j < cblk_h; ++j) {
- float* restrict tiledp2 = tiledp;
+ float* OPJ_RESTRICT tiledp2 = tiledp;
for (i = 0; i < cblk_w; ++i) {
float tmp = *datap * band->stepsize;
*tiledp2 = tmp;
diff --git a/indra/libopenjpeg/t1_generate_luts.c b/indra/libopenjpeg/t1_generate_luts.c
index 39880414fb..605709125a 100644
--- a/indra/libopenjpeg/t1_generate_luts.c
+++ b/indra/libopenjpeg/t1_generate_luts.c
@@ -194,7 +194,7 @@ int main(){
printf("/* This file was automatically generated by t1_generate_luts.c */\n\n");
- // lut_ctxno_zc
+ /* lut_ctxno_zc */
for (j = 0; j < 4; ++j) {
for (i = 0; i < 256; ++i) {
int orient = j;
@@ -215,7 +215,7 @@ int main(){
}
printf("%i\n};\n\n", lut_ctxno_zc[1023]);
- // lut_ctxno_sc
+ /* lut_ctxno_sc */
printf("static char lut_ctxno_sc[256] = {\n ");
for (i = 0; i < 255; ++i) {
printf("0x%x, ", t1_init_ctxno_sc(i << 4));
@@ -224,7 +224,7 @@ int main(){
}
printf("0x%x\n};\n\n", t1_init_ctxno_sc(255 << 4));
- // lut_spb
+ /* lut_spb */
printf("static char lut_spb[256] = {\n ");
for (i = 0; i < 255; ++i) {
printf("%i, ", t1_init_spb(i << 4));
diff --git a/indra/libopenjpeg/t2.c b/indra/libopenjpeg/t2.c
index cae29f09b1..2585c3d56a 100644
--- a/indra/libopenjpeg/t2.c
+++ b/indra/libopenjpeg/t2.c
@@ -30,6 +30,7 @@
*/
#include "opj_includes.h"
+#include
/** @defgroup T2 T2 - Implementation of a tier-2 coding */
/*@{*/
@@ -340,13 +341,15 @@ static int t2_decode_packet(opj_t2_t* t2, unsigned char *src, int len, opj_tcd_t
int precno = pi->precno; /* precinct value */
int layno = pi->layno; /* quality layer value */
- opj_tcd_resolution_t* res = &tile->comps[compno].resolutions[resno];
-
unsigned char *hd = NULL;
int present;
opj_bio_t *bio = NULL; /* BIO component */
-
+
+ opj_tcd_resolution_t* res;
+ assert(&tile->comps[compno] != NULL);
+ res = &tile->comps[compno].resolutions[resno];
+
if (layno == 0) {
for (bandno = 0; bandno < res->numbands; bandno++) {
opj_tcd_band_t *band = &res->bands[bandno];
diff --git a/indra/libopenjpeg/tcd.c b/indra/libopenjpeg/tcd.c
index c19b3eb6a9..4ced7aaff3 100644
--- a/indra/libopenjpeg/tcd.c
+++ b/indra/libopenjpeg/tcd.c
@@ -1507,7 +1507,7 @@ opj_bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno
for(j = res->y0; j < res->y1; ++j) {
for(i = res->x0; i < res->x1; ++i) {
float tmp = ((float*)tilec->data)[i - res->x0 + (j - res->y0) * tw];
- int v = lrintf(tmp);
+ int v = opj_lrintf(tmp);
v += adjust;
imagec->data[(i - offset_x) + (j - offset_y) * w] = int_clamp(v, min, max);
}
diff --git a/indra/libpathing/CMakeLists.txt b/indra/libpathing/CMakeLists.txt
index 35086c7160..aefe1a2acd 100644
--- a/indra/libpathing/CMakeLists.txt
+++ b/indra/libpathing/CMakeLists.txt
@@ -30,5 +30,8 @@ set_source_files_properties(${libpathing_HEADER_FILES}
PROPERTIES HEADER_FILE_ONLY TRUE)
add_library(nd_Pathing STATIC ${libpathing_SOURCE_FILES} ${libpathing_HEADER_FILES} )
-add_dependencies(nd_Pathing prepare)
+target_link_libraries(nd_Pathing
+ PUBLIC
+ llcommon
+)
diff --git a/indra/libpathing/llpathinglib.cpp b/indra/libpathing/llpathinglib.cpp
index 19c0bff0ff..041311de9a 100644
--- a/indra/libpathing/llpathinglib.cpp
+++ b/indra/libpathing/llpathinglib.cpp
@@ -1,4 +1,3 @@
-#include "sys.h"
#include "llpathinglib.h"
void LLPathingLib::initSystem()
diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp
index e016b47906..0a85aff0e3 100644
--- a/indra/llappearance/llavatarappearance.cpp
+++ b/indra/llappearance/llavatarappearance.cpp
@@ -24,11 +24,6 @@
* $/LicenseInfo$
*/
-#if LL_MSVC
-// disable warning about boost::lexical_cast returning uninitialized data
-// when it fails to parse the string
-#pragma warning (disable:4701)
-#endif
#include "linden_common.h"
@@ -44,6 +39,8 @@
#include "llstl.h"
#include "lltexglobalcolor.h"
#include "llwearabledata.h"
+#include "boost/bind.hpp"
+#include "boost/tokenizer.hpp"
#if LL_MSVC
@@ -51,8 +48,6 @@
#pragma warning (disable:4702)
#endif
-#include
-
using namespace LLAvatarAppearanceDefines;
//-----------------------------------------------------------------------------
@@ -81,13 +76,17 @@ class LLAvatarBoneInfo
~LLAvatarBoneInfo()
{
std::for_each(mChildList.begin(), mChildList.end(), DeletePointer());
+ mChildList.clear();
}
BOOL parseXml(LLXmlTreeNode* node);
private:
std::string mName;
+ std::string mSupport;
+ std::string mAliases;
BOOL mIsJoint;
LLVector3 mPos;
+ LLVector3 mEnd;
LLVector3 mRot;
LLVector3 mScale;
LLVector3 mPivot;
@@ -108,6 +107,7 @@ class LLAvatarSkeletonInfo
~LLAvatarSkeletonInfo()
{
std::for_each(mBoneInfoList.begin(), mBoneInfoList.end(), DeletePointer());
+ mBoneInfoList.clear();
}
BOOL parseXml(LLXmlTreeNode* node);
S32 getNumBones() const { return mNumBones; }
@@ -116,6 +116,7 @@ class LLAvatarSkeletonInfo
private:
S32 mNumBones;
S32 mNumCollisionVolumes;
+ LLAvatarAppearance::joint_alias_map_t mJointAliasMap;
typedef std::vector bone_info_list_t;
bone_info_list_t mBoneInfoList;
};
@@ -132,14 +133,25 @@ LLAvatarAppearance::LLAvatarXmlInfo::LLAvatarXmlInfo()
LLAvatarAppearance::LLAvatarXmlInfo::~LLAvatarXmlInfo()
{
std::for_each(mMeshInfoList.begin(), mMeshInfoList.end(), DeletePointer());
+ mMeshInfoList.clear();
+
std::for_each(mSkeletalDistortionInfoList.begin(), mSkeletalDistortionInfoList.end(), DeletePointer());
+ mSkeletalDistortionInfoList.clear();
+
std::for_each(mAttachmentInfoList.begin(), mAttachmentInfoList.end(), DeletePointer());
+ mAttachmentInfoList.clear();
+
delete_and_clear(mTexSkinColorInfo);
delete_and_clear(mTexHairColorInfo);
delete_and_clear(mTexEyeColorInfo);
std::for_each(mLayerInfoList.begin(), mLayerInfoList.end(), DeletePointer());
+ mLayerInfoList.clear();
+
std::for_each(mDriverInfoList.begin(), mDriverInfoList.end(), DeletePointer());
+ mDriverInfoList.clear();
+
std::for_each(mMorphMaskInfoList.begin(), mMorphMaskInfoList.end(), DeletePointer());
+ mMorphMaskInfoList.clear();
}
@@ -167,7 +179,10 @@ LLAvatarAppearance::LLAvatarAppearance(LLWearableData* wearable_data) :
mPelvisToFoot(0.f),
mHeadOffset(),
mRoot(NULL),
- mWearableData(wearable_data)
+ mWearableData(wearable_data),
+ mNumBones(0),
+ mIsBuilt(FALSE),
+ mInitFlags(0)
{
llassert_always(mWearableData);
mBakedTextureDatas.resize(LLAvatarAppearanceDefines::BAKED_NUM_INDICES);
@@ -180,8 +195,6 @@ LLAvatarAppearance::LLAvatarAppearance(LLWearableData* wearable_data) :
mBakedTextureDatas[i].mMaskTexName = 0;
mBakedTextureDatas[i].mTextureIndex = LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::bakedToLocalTextureIndex((LLAvatarAppearanceDefines::EBakedTextureIndex)i);
}
-
- mIsBuilt = FALSE;
}
// virtual
@@ -193,8 +206,9 @@ void LLAvatarAppearance::initInstance()
mRoot = createAvatarJoint();
mRoot->setName( "mRoot" );
- for (LLAvatarAppearanceDictionary::MeshEntries::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getMeshEntries().begin();
- iter != LLAvatarAppearanceDictionary::getInstance()->getMeshEntries().end();
+ const auto& mesh_entries = LLAvatarAppearanceDictionary::getInstance()->getMeshEntries();
+ for (LLAvatarAppearanceDictionary::MeshEntries::const_iterator iter = mesh_entries.begin();
+ iter != mesh_entries.end();
++iter)
{
const EMeshIndex mesh_index = iter->first;
@@ -211,7 +225,7 @@ void LLAvatarAppearance::initInstance()
for (U32 lod = 0; lod < mesh_dict->mLOD; lod++)
{
LLAvatarJointMesh* mesh = createAvatarJointMesh();
- std::string mesh_name = "m" + mesh_dict->mName + boost::lexical_cast(lod);
+ std::string mesh_name = fmt::format(FMT_STRING("m{:s}{:d}"), mesh_dict->mName, lod);
// We pre-pended an m - need to capitalize first character for camelCase
mesh_name[1] = toupper(mesh_name[1]);
mesh->setName(mesh_name);
@@ -239,8 +253,8 @@ void LLAvatarAppearance::initInstance()
//-------------------------------------------------------------------------
// associate baked textures with meshes
//-------------------------------------------------------------------------
- for (LLAvatarAppearanceDictionary::MeshEntries::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getMeshEntries().begin();
- iter != LLAvatarAppearanceDictionary::getInstance()->getMeshEntries().end();
+ for (LLAvatarAppearanceDictionary::MeshEntries::const_iterator iter = mesh_entries.begin();
+ iter != mesh_entries.end();
++iter)
{
const EMeshIndex mesh_index = iter->first;
@@ -264,6 +278,8 @@ void LLAvatarAppearance::initInstance()
}
buildCharacter();
+ mInitFlags |= 1<<0;
+
}
// virtual
@@ -279,7 +295,7 @@ LLAvatarAppearance::~LLAvatarAppearance()
mBakedTextureDatas[i].mJointMeshes.clear();
for (morph_list_t::iterator iter2 = mBakedTextureDatas[i].mMaskedMorphs.begin();
- iter2 != mBakedTextureDatas[i].mMaskedMorphs.end(); iter2++)
+ iter2 != mBakedTextureDatas[i].mMaskedMorphs.end(); ++iter2)
{
LLMaskedMorph* masked_morph = (*iter2);
delete masked_morph;
@@ -314,36 +330,49 @@ LLAvatarAppearance::~LLAvatarAppearance()
//static
void LLAvatarAppearance::initClass()
{
- std::string xmlFile;
+ initClass("","");
+}
- xmlFile = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,AVATAR_DEFAULT_CHAR) + "_lad.xml";
- BOOL success = sXMLTree.parseFile( xmlFile, FALSE );
+//static
+void LLAvatarAppearance::initClass(const std::string& avatar_file_name_arg, const std::string& skeleton_file_name_arg)
+{
+ std::string avatar_file_name;
+
+ if (!avatar_file_name_arg.empty())
+ {
+ avatar_file_name = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,avatar_file_name_arg);
+ }
+ else
+ {
+ avatar_file_name = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,AVATAR_DEFAULT_CHAR + "_lad.xml");
+ }
+ BOOL success = sXMLTree.parseFile( avatar_file_name, FALSE );
if (!success)
{
- LL_ERRS() << "Problem reading avatar configuration file:" << xmlFile << LL_ENDL;
+ LL_ERRS() << "Problem reading avatar configuration file:" << avatar_file_name << LL_ENDL;
}
// now sanity check xml file
LLXmlTreeNode* root = sXMLTree.getRoot();
if (!root)
{
- LL_ERRS() << "No root node found in avatar configuration file: " << xmlFile << LL_ENDL;
+ LL_ERRS() << "No root node found in avatar configuration file: " << avatar_file_name << LL_ENDL;
return;
}
//-------------------------------------------------------------------------
- // (root)
+ // (root)
//-------------------------------------------------------------------------
if( !root->hasName( "linden_avatar" ) )
{
- LL_ERRS() << "Invalid avatar file header: " << xmlFile << LL_ENDL;
+ LL_ERRS() << "Invalid avatar file header: " << avatar_file_name << LL_ENDL;
}
std::string version;
static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version");
- if( !root->getFastAttributeString( version_string, version ) || (version != "1.0") )
+ if( !root->getFastAttributeString( version_string, version ) || ((version != "1.0") && (version != "2.0")))
{
- LL_ERRS() << "Invalid avatar file version: " << version << " in file: " << xmlFile << LL_ENDL;
+ LL_ERRS() << "Invalid avatar file version: " << version << " in file: " << avatar_file_name << LL_ENDL;
}
S32 wearable_def_version = 1;
@@ -351,21 +380,22 @@ void LLAvatarAppearance::initClass()
root->getFastAttributeS32( wearable_definition_version_string, wearable_def_version );
LLWearable::setCurrentDefinitionVersion( wearable_def_version );
- std::string mesh_file_name;
-
LLXmlTreeNode* skeleton_node = root->getChildByName( "skeleton" );
if (!skeleton_node)
{
- LL_ERRS() << "No skeleton in avatar configuration file: " << xmlFile << LL_ENDL;
+ LL_ERRS() << "No skeleton in avatar configuration file: " << avatar_file_name << LL_ENDL;
return;
}
-
- std::string skeleton_file_name;
- static LLStdStringHandle file_name_string = LLXmlTree::addAttributeString("file_name");
- if (!skeleton_node->getFastAttributeString(file_name_string, skeleton_file_name))
- {
- LL_ERRS() << "No file name in skeleton node in avatar config file: " << xmlFile << LL_ENDL;
- }
+
+ std::string skeleton_file_name = skeleton_file_name_arg;
+ if (skeleton_file_name.empty())
+ {
+ static LLStdStringHandle file_name_string = LLXmlTree::addAttributeString("file_name");
+ if (!skeleton_node->getFastAttributeString(file_name_string, skeleton_file_name))
+ {
+ LL_ERRS() << "No file name in skeleton node in avatar config file: " << avatar_file_name << LL_ENDL;
+ }
+ }
std::string skeleton_path;
skeleton_path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,skeleton_file_name);
@@ -428,11 +458,56 @@ void LLAvatarAppearance::cleanupClass()
using namespace LLAvatarAppearanceDefines;
+void LLAvatarAppearance::compareJointStateMaps(joint_state_map_t& last_state,
+ joint_state_map_t& curr_state)
+{
+ if (!last_state.empty() && (last_state != curr_state))
+ {
+ S32 diff_count = 0;
+ joint_state_map_t::iterator it;
+ for (it=last_state.begin(); it != last_state.end(); ++it)
+ {
+ const std::string& key = it->first;
+ if (last_state[key] != curr_state[key])
+ {
+ LL_DEBUGS("AvatarBodySize") << "BodySize change " << key << " " << last_state[key] << "->" << curr_state[key] << LL_ENDL;
+ diff_count++;
+ }
+ }
+ if (diff_count > 0)
+ {
+ LL_DEBUGS("AvatarBodySize") << "Total of BodySize changes " << diff_count << LL_ENDL;
+ }
+
+ }
+}
+
//------------------------------------------------------------------------
// The viewer can only suggest a good size for the agent,
// the simulator will keep it inside a reasonable range.
void LLAvatarAppearance::computeBodySize()
{
+ mLastBodySizeState = mCurrBodySizeState;
+
+ mCurrBodySizeState["mPelvis scale"] = mPelvisp->getScale();
+ mCurrBodySizeState["mSkull pos"] = mSkullp->getPosition();
+ mCurrBodySizeState["mSkull scale"] = mSkullp->getScale();
+ mCurrBodySizeState["mNeck pos"] = mNeckp->getPosition();
+ mCurrBodySizeState["mNeck scale"] = mNeckp->getScale();
+ mCurrBodySizeState["mChest pos"] = mChestp->getPosition();
+ mCurrBodySizeState["mChest scale"] = mChestp->getScale();
+ mCurrBodySizeState["mHead pos"] = mHeadp->getPosition();
+ mCurrBodySizeState["mHead scale"] = mHeadp->getScale();
+ mCurrBodySizeState["mTorso pos"] = mTorsop->getPosition();
+ mCurrBodySizeState["mTorso scale"] = mTorsop->getScale();
+ mCurrBodySizeState["mHipLeft pos"] = mHipLeftp->getPosition();
+ mCurrBodySizeState["mHipLeft scale"] = mHipLeftp->getScale();
+ mCurrBodySizeState["mKneeLeft pos"] = mKneeLeftp->getPosition();
+ mCurrBodySizeState["mKneeLeft scale"] = mKneeLeftp->getScale();
+ mCurrBodySizeState["mAnkleLeft pos"] = mAnkleLeftp->getPosition();
+ mCurrBodySizeState["mAnkleLeft scale"] = mAnkleLeftp->getScale();
+ mCurrBodySizeState["mFootLeft pos"] = mFootLeftp->getPosition();
+
LLVector3 pelvis_scale = mPelvisp->getScale();
// some of the joints have not been cached
@@ -489,29 +564,11 @@ void LLAvatarAppearance::computeBodySize()
mAvatarOffset.mV[VX] = 0.0f;
mAvatarOffset.mV[VY] = 0.0f;
- // Certain configurations of avatars can force the overall height (with offset) to go negative.
- // Enforce a constraint to make sure we don't go below 0.1 meters.
- // Camera positioning and other things start to break down when your avatar is "walking" while being fully underground
- if (new_body_size.mV[VZ] + mAvatarOffset.mV[VZ] < 0.1f)
- {
- mAvatarOffset.mV[VZ] = -(new_body_size.mV[VZ] - 0.11f); // avoid floating point rounding making the above check continue to fail.
-
- llassert(new_body_size.mV[VZ] + mAvatarOffset.mV[VZ] >= 0.1f);
-
- if (mWearableData && isSelf())
- {
- LLWearable* shape = mWearableData->getWearable(LLWearableType::WT_SHAPE, 0);
- if (shape)
- {
- shape->setVisualParamWeight(AVATAR_HOVER, mAvatarOffset.mV[VZ], false);
- }
- }
- }
-
if (new_body_size != mBodySize || old_offset != mAvatarOffset)
{
mBodySize = new_body_size;
- bodySizeChanged();
+
+ compareJointStateMaps(mLastBodySizeState, mCurrBodySizeState);
}
}
@@ -547,7 +604,7 @@ BOOL LLAvatarAppearance::parseSkeletonFile(const std::string& filename)
std::string version;
static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version");
- if( !root->getFastAttributeString( version_string, version ) || (version != "1.0") )
+ if( !root->getFastAttributeString( version_string, version ) || ((version != "1.0") && (version != "2.0")))
{
LL_ERRS() << "Invalid avatar skeleton file version: " << version << " in file: " << filename << LL_ENDL;
return FALSE;
@@ -563,6 +620,12 @@ BOOL LLAvatarAppearance::setupBone(const LLAvatarBoneInfo* info, LLJoint* parent
{
LLJoint* joint = NULL;
+ LL_DEBUGS("BVH") << "bone info: name " << info->mName
+ << " isJoint " << info->mIsJoint
+ << " volume_num " << volume_num
+ << " joint_num " << joint_num
+ << LL_ENDL;
+
if (info->mIsJoint)
{
joint = getCharacterJoint(joint_num);
@@ -577,7 +640,7 @@ BOOL LLAvatarAppearance::setupBone(const LLAvatarBoneInfo* info, LLJoint* parent
{
if (volume_num >= (S32)mCollisionVolumes.size())
{
- LL_WARNS() << "Too many bones" << LL_ENDL;
+ LL_WARNS() << "Too many collision volumes" << LL_ENDL;
return FALSE;
}
joint = (mCollisionVolumes[volume_num]);
@@ -585,28 +648,34 @@ BOOL LLAvatarAppearance::setupBone(const LLAvatarBoneInfo* info, LLJoint* parent
}
// add to parent
- if (parent)
+ if (parent && (joint->getParent()!=parent))
{
parent->addChild( joint );
}
+ // SL-315
joint->setPosition(info->mPos);
+ joint->setDefaultPosition(info->mPos);
joint->setRotation(mayaQ(info->mRot.mV[VX], info->mRot.mV[VY],
info->mRot.mV[VZ], LLQuaternion::XYZ));
joint->setScale(info->mScale);
+ joint->setDefaultScale(info->mScale);
+ joint->setSupport(info->mSupport);
+ joint->setEnd(info->mEnd);
- joint->setDefaultFromCurrentXform();
-
if (info->mIsJoint)
{
joint->setSkinOffset( info->mPivot );
+ joint->setJointNum(joint_num);
joint_num++;
}
else // collision volume
{
+ joint->setJointNum(mNumBones+volume_num);
volume_num++;
}
+
// setup children
LLAvatarBoneInfo::child_list_t::const_iterator iter;
for (iter = info->mChildList.begin(); iter != info->mChildList.end(); ++iter)
@@ -626,18 +695,12 @@ BOOL LLAvatarAppearance::setupBone(const LLAvatarBoneInfo* info, LLJoint* parent
//-----------------------------------------------------------------------------
BOOL LLAvatarAppearance::allocateCharacterJoints( U32 num )
{
- clearSkeleton();
-
- for(S32 joint_num = 0; joint_num < (S32)num; joint_num++)
- {
- mSkeleton.push_back(createAvatarJoint(joint_num));
- }
-
-
- if (mSkeleton.empty() || !mSkeleton[0])
- {
- return FALSE;
- }
+ if (mSkeleton.size() != num)
+ {
+ clearSkeleton();
+ mSkeleton = avatar_joint_list_t(num,NULL);
+ mNumBones = num;
+ }
return TRUE;
}
@@ -650,6 +713,8 @@ BOOL LLAvatarAppearance::buildSkeleton(const LLAvatarSkeletonInfo *info)
{
if (!info)
return FALSE;
+ LL_DEBUGS("BVH") << "numBones " << info->mNumBones << " numCollisionVolumes " << info->mNumCollisionVolumes << LL_ENDL;
+
//-------------------------------------------------------------------------
// allocate joints
//-------------------------------------------------------------------------
@@ -676,8 +741,8 @@ BOOL LLAvatarAppearance::buildSkeleton(const LLAvatarSkeletonInfo *info)
LLAvatarSkeletonInfo::bone_info_list_t::const_iterator iter;
for (iter = info->mBoneInfoList.begin(); iter != info->mBoneInfoList.end(); ++iter)
{
- LLAvatarBoneInfo *info = *iter;
- if (!setupBone(info, NULL, current_volume_num, current_joint_num))
+ LLAvatarBoneInfo *bone_info = *iter;
+ if (!setupBone(bone_info, NULL, current_volume_num, current_joint_num))
{
LL_ERRS() << "Error parsing bone in skeleton file" << LL_ENDL;
return FALSE;
@@ -696,6 +761,42 @@ void LLAvatarAppearance::clearSkeleton()
mSkeleton.clear();
}
+//------------------------------------------------------------------------
+// addPelvisFixup
+//------------------------------------------------------------------------
+void LLAvatarAppearance::addPelvisFixup( F32 fixup, const LLUUID& mesh_id )
+{
+ LLVector3 pos(0.0,0.0,fixup);
+ mPelvisFixups.add(mesh_id,pos);
+}
+
+//------------------------------------------------------------------------
+// addPelvisFixup
+//------------------------------------------------------------------------
+void LLAvatarAppearance::removePelvisFixup( const LLUUID& mesh_id )
+{
+ mPelvisFixups.remove(mesh_id);
+}
+
+//------------------------------------------------------------------------
+// hasPelvisFixup
+//------------------------------------------------------------------------
+bool LLAvatarAppearance::hasPelvisFixup( F32& fixup, LLUUID& mesh_id ) const
+{
+ LLVector3 pos;
+ if (mPelvisFixups.findActiveOverride(mesh_id,pos))
+ {
+ fixup = pos[2];
+ return true;
+ }
+ return false;
+}
+
+bool LLAvatarAppearance::hasPelvisFixup( F32& fixup ) const
+{
+ LLUUID mesh_id;
+ return hasPelvisFixup( fixup, mesh_id );
+}
//-----------------------------------------------------------------------------
// LLAvatarAppearance::buildCharacter()
// Deferred initialization and rebuild of the avatar.
@@ -821,11 +922,11 @@ void LLAvatarAppearance::buildCharacter()
//-----------------------------------------------------------------------------
// loadAvatar()
//-----------------------------------------------------------------------------
-//static LLFastTimer::DeclareTimer FTM_LOAD_AVATAR("Load Avatar");
+//static LLTrace::BlockTimerStatHandle FTM_LOAD_AVATAR("Load Avatar");
BOOL LLAvatarAppearance::loadAvatar()
{
-// LLFastTimer t(FTM_LOAD_AVATAR);
+// LL_RECORD_BLOCK_TIME(FTM_LOAD_AVATAR);
// avatar_skeleton.xml
if( !buildSkeleton(sAvatarSkeletonInfo) )
@@ -941,7 +1042,7 @@ BOOL LLAvatarAppearance::loadAvatar()
addVisualParam( driver_param );
driver_param->setParamLocation(isSelf() ? LOC_AV_SELF : LOC_AV_OTHER);
LLVisualParam*(LLAvatarAppearance::*avatar_function)(S32)const = &LLAvatarAppearance::getVisualParam;
- if( !driver_param->linkDrivenParams(boost::bind(avatar_function,(LLAvatarAppearance*)this,_1 ), false))
+ if( !driver_param->linkDrivenParams(std::bind(avatar_function,(LLAvatarAppearance*)this, std::placeholders::_1 ), false))
{
LL_WARNS() << "could not link driven params for avatar " << getID().asString() << " param id: " << driver_param->getID() << LL_ENDL;
continue;
@@ -1100,6 +1201,7 @@ BOOL LLAvatarAppearance::loadMeshNodes()
{
// This should never happen
LL_WARNS("Avatar") << "Could not find avatar mesh: " << info->mReferenceMeshName << LL_ENDL;
+ return FALSE;
}
}
else
@@ -1115,7 +1217,7 @@ BOOL LLAvatarAppearance::loadMeshNodes()
}
// Multimap insert
- mPolyMeshes.insert(std::make_pair(info->mMeshFileName, poly_mesh));
+ mPolyMeshes.emplace(info->mMeshFileName, poly_mesh);
mesh->setMesh( poly_mesh );
mesh->setLOD( info->mMinPixelArea );
@@ -1236,6 +1338,10 @@ LLJoint *LLAvatarAppearance::getCharacterJoint( U32 num )
{
return NULL;
}
+ if (!mSkeleton[num])
+ {
+ mSkeleton[num] = createAvatarJoint();
+ }
return mSkeleton[num];
}
@@ -1261,12 +1367,12 @@ LLVector3 LLAvatarAppearance::getVolumePos(S32 joint_index, LLVector3& volume_of
//-----------------------------------------------------------------------------
// findCollisionVolume()
//-----------------------------------------------------------------------------
-LLJoint* LLAvatarAppearance::findCollisionVolume(U32 volume_id)
+LLJoint* LLAvatarAppearance::findCollisionVolume(S32 volume_id)
{
//SNOW-488: As mNumCollisionVolumes is a S32 and we are casting from a U32 to a S32
//to compare we also need to be sure of the wrap around case producing (S32) <0
//or in terms of the U32 an out of bounds index in the array.
- if ((S32)volume_id > (S32)mCollisionVolumes.size() || (S32)volume_id<0)
+ if ((S32)volume_id > (S32)mCollisionVolumes.size() || volume_id<0)
{
return NULL;
}
@@ -1454,6 +1560,21 @@ BOOL LLAvatarAppearance::teToColorParams( ETextureIndex te, U32 *param_name )
param_name[1] = 1072; //"tattoo_green";
param_name[2] = 1073; //"tattoo_blue";
break;
+ case TEX_HEAD_UNIVERSAL_TATTOO:
+ case TEX_UPPER_UNIVERSAL_TATTOO:
+ case TEX_LOWER_UNIVERSAL_TATTOO:
+ case TEX_SKIRT_TATTOO:
+ case TEX_HAIR_TATTOO:
+ case TEX_EYES_TATTOO:
+ case TEX_LEFT_ARM_TATTOO:
+ case TEX_LEFT_LEG_TATTOO:
+ case TEX_AUX1_TATTOO:
+ case TEX_AUX2_TATTOO:
+ case TEX_AUX3_TATTOO:
+ param_name[0] = 1238; //"tattoo_universal_red";
+ param_name[1] = 1239; //"tattoo_universal_green";
+ param_name[2] = 1240; //"tattoo_universal_blue";
+ break;
default:
llassert(0);
@@ -1535,21 +1656,24 @@ LLTexLayerSet* LLAvatarAppearance::getAvatarLayerSet(EBakedTextureIndex baked_in
//-----------------------------------------------------------------------------
BOOL LLAvatarAppearance::allocateCollisionVolumes( U32 num )
{
- delete_and_clear(mCollisionVolumes);
- mCollisionVolumes.reserve(num);
-
- LLAvatarJointCollisionVolume* cv;
- for (U32 i = 0; i < num; ++i)
+ if(num != mCollisionVolumes.size() )
{
- cv = new LLAvatarJointCollisionVolume();
- if (cv)
- {
- mCollisionVolumes.push_back(cv);
- }
- else
+ delete_and_clear(mCollisionVolumes);
+ mCollisionVolumes.reserve(num);
+
+ LLAvatarJointCollisionVolume* cv;
+ for (U32 i = 0; i < num; ++i)
{
- delete_and_clear(mCollisionVolumes);
- return false;
+ cv = new LLAvatarJointCollisionVolume();
+ if (cv)
+ {
+ mCollisionVolumes.push_back(cv);
+ }
+ else
+ {
+ delete_and_clear(mCollisionVolumes);
+ return false;
+ }
}
}
return TRUE;
@@ -1569,6 +1693,9 @@ BOOL LLAvatarBoneInfo::parseXml(LLXmlTreeNode* node)
LL_WARNS() << "Bone without name" << LL_ENDL;
return FALSE;
}
+
+ static LLStdStringHandle aliases_string = LLXmlTree::addAttributeString("aliases");
+ node->getFastAttributeString(aliases_string, mAliases ); //Aliases are not required.
}
else if (node->hasName("collision_volume"))
{
@@ -1606,6 +1733,20 @@ BOOL LLAvatarBoneInfo::parseXml(LLXmlTreeNode* node)
return FALSE;
}
+ static LLStdStringHandle end_string = LLXmlTree::addAttributeString("end");
+ if (!node->getFastAttributeVector3(end_string, mEnd))
+ {
+ LL_WARNS() << "Bone without end " << mName << LL_ENDL;
+ mEnd = LLVector3(0.0f, 0.0f, 0.0f);
+ }
+
+ static LLStdStringHandle support_string = LLXmlTree::addAttributeString("support");
+ if (!node->getFastAttributeString(support_string,mSupport))
+ {
+ LL_WARNS() << "Bone without support " << mName << LL_ENDL;
+ mSupport = "base";
+ }
+
if (mIsJoint)
{
static LLStdStringHandle pivot_string = LLXmlTree::addAttributeString("pivot");
@@ -1661,6 +1802,75 @@ BOOL LLAvatarSkeletonInfo::parseXml(LLXmlTreeNode* node)
return TRUE;
}
+//Make aliases for joint and push to map.
+void LLAvatarAppearance::makeJointAliases(LLAvatarBoneInfo *bone_info)
+{
+ if (! bone_info->mIsJoint )
+ {
+ return;
+ }
+
+ std::string bone_name = bone_info->mName;
+ mJointAliasMap[bone_name] = bone_name; //Actual name is a valid alias.
+
+ std::string aliases = bone_info->mAliases;
+
+ boost::char_separator sep(" ");
+ boost::tokenizer > tok(aliases, sep);
+ for(boost::tokenizer >::iterator i = tok.begin(); i != tok.end(); ++i)
+ {
+ if ( mJointAliasMap.find(*i) != mJointAliasMap.end() )
+ {
+ LL_WARNS() << "avatar skeleton: Joint alias \"" << *i << "\" remapped from " << mJointAliasMap[*i] << " to " << bone_name << LL_ENDL;
+ }
+ mJointAliasMap[*i] = bone_name;
+ }
+
+ LLAvatarBoneInfo::child_list_t::const_iterator iter;
+ for (iter = bone_info->mChildList.begin(); iter != bone_info->mChildList.end(); ++iter)
+ {
+ makeJointAliases( *iter );
+ }
+}
+
+const LLAvatarAppearance::joint_alias_map_t& LLAvatarAppearance::getJointAliases ()
+{
+ LLAvatarAppearance::joint_alias_map_t alias_map;
+ if (mJointAliasMap.empty())
+ {
+
+ LLAvatarSkeletonInfo::bone_info_list_t::const_iterator iter;
+ for (iter = sAvatarSkeletonInfo->mBoneInfoList.begin();
+ iter != sAvatarSkeletonInfo->mBoneInfoList.end();
+ ++iter)
+ {
+ //LLAvatarBoneInfo *bone_info = *iter;
+ makeJointAliases( *iter );
+ }
+
+ LLAvatarXmlInfo::attachment_info_list_t::iterator attach_iter;
+ for (attach_iter = sAvatarXmlInfo->mAttachmentInfoList.begin();
+ attach_iter != sAvatarXmlInfo->mAttachmentInfoList.end();
+ ++attach_iter)
+ {
+ LLAvatarXmlInfo::LLAvatarAttachmentInfo *info = *attach_iter;
+ std::string bone_name = info->mName;
+
+ // Also accept the name with spaces substituted with
+ // underscores. This gives a mechanism for referencing such joints
+ // in daes, which don't allow spaces.
+ std::string sub_space_to_underscore = bone_name;
+ LLStringUtil::replaceChar(sub_space_to_underscore, ' ', '_');
+ if (sub_space_to_underscore != bone_name)
+ {
+ mJointAliasMap[sub_space_to_underscore] = bone_name;
+ }
+ }
+ }
+
+ return mJointAliasMap;
+}
+
//-----------------------------------------------------------------------------
// parseXmlSkeletonNode(): parses nodes from XML tree
@@ -1691,7 +1901,7 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlSkeletonNode(LLXmlTreeNode* ro
{
LL_WARNS() << "Unknown param type." << LL_ENDL;
}
- continue;
+ return FALSE;
}
LLPolySkeletalDistortionInfo *info = new LLPolySkeletalDistortionInfo;
@@ -1716,7 +1926,7 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlSkeletonNode(LLXmlTreeNode* ro
{
LL_WARNS() << "No name supplied for attachment point." << LL_ENDL;
delete info;
- continue;
+ return FALSE;
}
static LLStdStringHandle joint_string = LLXmlTree::addAttributeString("joint");
@@ -1724,7 +1934,7 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlSkeletonNode(LLXmlTreeNode* ro
{
LL_WARNS() << "No bone declared in attachment point " << info->mName << LL_ENDL;
delete info;
- continue;
+ return FALSE;
}
static LLStdStringHandle position_string = LLXmlTree::addAttributeString("position");
@@ -1750,7 +1960,7 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlSkeletonNode(LLXmlTreeNode* ro
{
LL_WARNS() << "No id supplied for attachment point " << info->mName << LL_ENDL;
delete info;
- continue;
+ return FALSE;
}
static LLStdStringHandle slot_string = LLXmlTree::addAttributeString("pie_slice");
@@ -1836,7 +2046,7 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlMeshNodes(LLXmlTreeNode* root)
{
LL_WARNS() << "Unknown param type." << LL_ENDL;
}
- continue;
+ return FALSE;
}
LLPolyMorphTargetInfo *morphinfo = new LLPolyMorphTargetInfo();
@@ -1997,7 +2207,7 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlMorphNodes(LLXmlTreeNode* root
{
LL_WARNS() << "No name supplied for morph mask." << LL_ENDL;
delete info;
- continue;
+ return FALSE;
}
static LLStdStringHandle region_string = LLXmlTree::addAttributeString("body_region");
@@ -2005,7 +2215,7 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlMorphNodes(LLXmlTreeNode* root
{
LL_WARNS() << "No region supplied for morph mask." << LL_ENDL;
delete info;
- continue;
+ return FALSE;
}
static LLStdStringHandle layer_string = LLXmlTree::addAttributeString("layer");
@@ -2013,7 +2223,7 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlMorphNodes(LLXmlTreeNode* root
{
LL_WARNS() << "No layer supplied for morph mask." << LL_ENDL;
delete info;
- continue;
+ return FALSE;
}
// optional parameter. don't throw a warning if not present.
diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h
index f691d73783..3fa4c35137 100644
--- a/indra/llappearance/llavatarappearance.h
+++ b/indra/llappearance/llavatarappearance.h
@@ -35,6 +35,7 @@
#include "llviewervisualparam.h"
#include "llxmltree.h"
+#include //
class LLTexLayerSet;
class LLTexGlobalColor;
class LLTexGlobalColorInfo;
@@ -66,9 +67,11 @@ class LLAvatarAppearance : public LLCharacter
LLAvatarAppearance(LLWearableData* wearable_data);
virtual ~LLAvatarAppearance();
+ static void initClass(const std::string& avatar_file_name, const std::string& skeleton_file_name); // initializes static members
static void initClass(); // initializes static members
static void cleanupClass(); // Cleanup data that's only init'd once per class.
virtual void initInstance(); // Called after construction to initialize the instance.
+ S32 mInitFlags;
virtual BOOL loadSkeletonNode();
BOOL loadMeshNodes();
BOOL loadLayersets();
@@ -91,7 +94,7 @@ class LLAvatarAppearance : public LLCharacter
/*virtual*/ const char* getAnimationPrefix() { return "avatar"; }
/*virtual*/ LLVector3 getVolumePos(S32 joint_index, LLVector3& volume_offset);
- /*virtual*/ LLJoint* findCollisionVolume(U32 volume_id);
+ /*virtual*/ LLJoint* findCollisionVolume(S32 volume_id);
/*virtual*/ S32 getCollisionVolumeID(std::string &name);
/*virtual*/ LLPolyMesh* getHeadMesh();
/*virtual*/ LLPolyMesh* getUpperBodyMesh();
@@ -132,6 +135,7 @@ class LLAvatarAppearance : public LLCharacter
virtual LLAvatarJoint* createAvatarJoint() = 0;
virtual LLAvatarJoint* createAvatarJoint(S32 joint_num) = 0;
virtual LLAvatarJointMesh* createAvatarJointMesh() = 0;
+ void makeJointAliases(LLAvatarBoneInfo *bone_info);
public:
F32 getPelvisToFoot() const { return mPelvisToFoot; }
/*virtual*/ LLJoint* getRootJoint() { return mRoot; }
@@ -139,17 +143,27 @@ class LLAvatarAppearance : public LLCharacter
LLVector3 mHeadOffset; // current head position
LLAvatarJoint *mRoot;
- typedef std::map joint_map_t;
+ typedef std::vector > joint_map_t;
joint_map_t mJointMap;
-
+
+ typedef std::map joint_state_map_t;
+ joint_state_map_t mLastBodySizeState;
+ joint_state_map_t mCurrBodySizeState;
+ void compareJointStateMaps(joint_state_map_t& last_state,
+ joint_state_map_t& curr_state);
void computeBodySize();
+public:
+ typedef std::vector avatar_joint_list_t;
+ const avatar_joint_list_t& getSkeleton() { return mSkeleton; }
+ typedef std::map joint_alias_map_t;
+ const joint_alias_map_t& getJointAliases();
+
protected:
static BOOL parseSkeletonFile(const std::string& filename);
virtual void buildCharacter();
virtual BOOL loadAvatar();
- virtual void bodySizeChanged() = 0;
BOOL setupBone(const LLAvatarBoneInfo* info, LLJoint* parent, S32 ¤t_volume_num, S32 ¤t_joint_num);
BOOL allocateCharacterJoints(U32 num);
@@ -157,13 +171,20 @@ class LLAvatarAppearance : public LLCharacter
protected:
void clearSkeleton();
BOOL mIsBuilt; // state of deferred character building
- typedef std::vector avatar_joint_list_t;
+
avatar_joint_list_t mSkeleton;
-
+ LLVector3OverrideMap mPelvisFixups;
+ joint_alias_map_t mJointAliasMap;
+
//--------------------------------------------------------------------
// Pelvis height adjustment members.
//--------------------------------------------------------------------
public:
+ void addPelvisFixup( F32 fixup, const LLUUID& mesh_id );
+ void removePelvisFixup( const LLUUID& mesh_id );
+ bool hasPelvisFixup( F32& fixup, LLUUID& mesh_id ) const;
+ bool hasPelvisFixup( F32& fixup ) const;
+
LLVector3 mBodySize;
LLVector3 mAvatarOffset;
protected:
@@ -213,7 +234,7 @@ class LLAvatarAppearance : public LLCharacter
** RENDERING
**/
public:
- BOOL mIsDummy; // for special views
+ BOOL mIsDummy; // for special views and animated object controllers; local to viewer
//--------------------------------------------------------------------
// Morph masks
@@ -320,7 +341,7 @@ class LLAvatarAppearance : public LLCharacter
bool mIsLoaded;
bool mIsUsed;
LLAvatarAppearanceDefines::ETextureIndex mTextureIndex;
- U32 mMaskTexName;
+ LLImageGL::GLTextureName mMaskTexName;
// Stores pointers to the joint meshes that this baked texture deals with
avatar_joint_mesh_list_t mJointMeshes;
morph_list_t mMaskedMorphs;
@@ -337,6 +358,7 @@ class LLAvatarAppearance : public LLCharacter
// Collision volumes
//--------------------------------------------------------------------
public:
+ S32 mNumBones;
std::vector mCollisionVolumes;
protected:
BOOL allocateCollisionVolumes(U32 num);
diff --git a/indra/llappearance/llavatarappearancedefines.cpp b/indra/llappearance/llavatarappearancedefines.cpp
index f1c78946a1..5f3c7cdaad 100644
--- a/indra/llappearance/llavatarappearancedefines.cpp
+++ b/indra/llappearance/llavatarappearancedefines.cpp
@@ -27,8 +27,11 @@
#include "linden_common.h"
#include "llavatarappearancedefines.h"
-const S32 LLAvatarAppearanceDefines::SCRATCH_TEX_WIDTH = 512;
-const S32 LLAvatarAppearanceDefines::SCRATCH_TEX_HEIGHT = 512;
+#include "indra_constants.h"
+#include
+
+const S32 LLAvatarAppearanceDefines::SCRATCH_TEX_WIDTH = 1024;
+const S32 LLAvatarAppearanceDefines::SCRATCH_TEX_HEIGHT = 1024;
const S32 LLAvatarAppearanceDefines::IMPOSTOR_PERIOD = 2;
using namespace LLAvatarAppearanceDefines;
@@ -65,12 +68,30 @@ LLAvatarAppearanceDictionary::Textures::Textures()
addEntry(TEX_UPPER_TATTOO, new TextureEntry("upper_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_TATTOO));
addEntry(TEX_LOWER_TATTOO, new TextureEntry("lower_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_TATTOO));
+ addEntry(TEX_HEAD_UNIVERSAL_TATTOO, new TextureEntry("head_universal_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
+ addEntry(TEX_UPPER_UNIVERSAL_TATTOO, new TextureEntry("upper_universal_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
+ addEntry(TEX_LOWER_UNIVERSAL_TATTOO, new TextureEntry("lower_universal_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
+ addEntry(TEX_SKIRT_TATTOO, new TextureEntry("skirt_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
+ addEntry(TEX_HAIR_TATTOO, new TextureEntry("hair_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
+ addEntry(TEX_EYES_TATTOO, new TextureEntry("eyes_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
+ addEntry(TEX_LEFT_ARM_TATTOO, new TextureEntry("leftarm_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
+ addEntry(TEX_LEFT_LEG_TATTOO, new TextureEntry("leftleg_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
+ addEntry(TEX_AUX1_TATTOO, new TextureEntry("aux1_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
+ addEntry(TEX_AUX2_TATTOO, new TextureEntry("aux2_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
+ addEntry(TEX_AUX3_TATTOO, new TextureEntry("aux3_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL));
+
+
addEntry(TEX_HEAD_BAKED, new TextureEntry("head-baked", FALSE, BAKED_HEAD, "head"));
addEntry(TEX_UPPER_BAKED, new TextureEntry("upper-baked", FALSE, BAKED_UPPER, "upper"));
addEntry(TEX_LOWER_BAKED, new TextureEntry("lower-baked", FALSE, BAKED_LOWER, "lower"));
addEntry(TEX_EYES_BAKED, new TextureEntry("eyes-baked", FALSE, BAKED_EYES, "eyes"));
addEntry(TEX_HAIR_BAKED, new TextureEntry("hair-baked", FALSE, BAKED_HAIR, "hair"));
addEntry(TEX_SKIRT_BAKED, new TextureEntry("skirt-baked", FALSE, BAKED_SKIRT, "skirt"));
+ addEntry(TEX_LEFT_ARM_BAKED, new TextureEntry("leftarm-baked", FALSE, BAKED_LEFT_ARM, "leftarm"));
+ addEntry(TEX_LEFT_LEG_BAKED, new TextureEntry("leftleg-baked", FALSE, BAKED_LEFT_LEG, "leftleg"));
+ addEntry(TEX_AUX1_BAKED, new TextureEntry("aux1-baked", FALSE, BAKED_AUX1, "aux1"));
+ addEntry(TEX_AUX2_BAKED, new TextureEntry("aux2-baked", FALSE, BAKED_AUX2, "aux2"));
+ addEntry(TEX_AUX3_BAKED, new TextureEntry("aux3-baked", FALSE, BAKED_AUX3, "aux3"));
}
LLAvatarAppearanceDictionary::BakedTextures::BakedTextures()
@@ -78,35 +99,60 @@ LLAvatarAppearanceDictionary::BakedTextures::BakedTextures()
// Baked textures
addEntry(BAKED_HEAD, new BakedEntry(TEX_HEAD_BAKED,
"head", "a4b9dc38-e13b-4df9-b284-751efb0566ff",
- 3, TEX_HEAD_BODYPAINT, TEX_HEAD_TATTOO, TEX_HEAD_ALPHA,
- 5, LLWearableType::WT_SHAPE, LLWearableType::WT_SKIN, LLWearableType::WT_HAIR, LLWearableType::WT_TATTOO, LLWearableType::WT_ALPHA));
+ 4, TEX_HEAD_BODYPAINT, TEX_HEAD_TATTOO, TEX_HEAD_ALPHA, TEX_HEAD_UNIVERSAL_TATTOO,
+ 6, LLWearableType::WT_SHAPE, LLWearableType::WT_SKIN, LLWearableType::WT_HAIR, LLWearableType::WT_TATTOO, LLWearableType::WT_ALPHA, LLWearableType::WT_UNIVERSAL));
addEntry(BAKED_UPPER, new BakedEntry(TEX_UPPER_BAKED,
"upper_body", "5943ff64-d26c-4a90-a8c0-d61f56bd98d4",
- 7, TEX_UPPER_SHIRT,TEX_UPPER_BODYPAINT, TEX_UPPER_JACKET,
- TEX_UPPER_GLOVES, TEX_UPPER_UNDERSHIRT, TEX_UPPER_TATTOO, TEX_UPPER_ALPHA,
- 8, LLWearableType::WT_SHAPE, LLWearableType::WT_SKIN, LLWearableType::WT_SHIRT, LLWearableType::WT_JACKET, LLWearableType::WT_GLOVES, LLWearableType::WT_UNDERSHIRT, LLWearableType::WT_TATTOO, LLWearableType::WT_ALPHA));
+ 8, TEX_UPPER_SHIRT,TEX_UPPER_BODYPAINT, TEX_UPPER_JACKET,
+ TEX_UPPER_GLOVES, TEX_UPPER_UNDERSHIRT, TEX_UPPER_TATTOO, TEX_UPPER_ALPHA, TEX_UPPER_UNIVERSAL_TATTOO,
+ 9, LLWearableType::WT_SHAPE, LLWearableType::WT_SKIN, LLWearableType::WT_SHIRT, LLWearableType::WT_JACKET, LLWearableType::WT_GLOVES, LLWearableType::WT_UNDERSHIRT, LLWearableType::WT_TATTOO, LLWearableType::WT_ALPHA, LLWearableType::WT_UNIVERSAL));
addEntry(BAKED_LOWER, new BakedEntry(TEX_LOWER_BAKED,
"lower_body", "2944ee70-90a7-425d-a5fb-d749c782ed7d",
- 8, TEX_LOWER_PANTS,TEX_LOWER_BODYPAINT,TEX_LOWER_SHOES, TEX_LOWER_SOCKS,
- TEX_LOWER_JACKET, TEX_LOWER_UNDERPANTS, TEX_LOWER_TATTOO, TEX_LOWER_ALPHA,
- 9, LLWearableType::WT_SHAPE, LLWearableType::WT_SKIN, LLWearableType::WT_PANTS, LLWearableType::WT_SHOES, LLWearableType::WT_SOCKS, LLWearableType::WT_JACKET, LLWearableType::WT_UNDERPANTS, LLWearableType::WT_TATTOO, LLWearableType::WT_ALPHA));
+ 9, TEX_LOWER_PANTS,TEX_LOWER_BODYPAINT,TEX_LOWER_SHOES, TEX_LOWER_SOCKS,
+ TEX_LOWER_JACKET, TEX_LOWER_UNDERPANTS, TEX_LOWER_TATTOO, TEX_LOWER_ALPHA, TEX_LOWER_UNIVERSAL_TATTOO,
+ 10, LLWearableType::WT_SHAPE, LLWearableType::WT_SKIN, LLWearableType::WT_PANTS, LLWearableType::WT_SHOES, LLWearableType::WT_SOCKS, LLWearableType::WT_JACKET, LLWearableType::WT_UNDERPANTS, LLWearableType::WT_TATTOO, LLWearableType::WT_ALPHA, LLWearableType::WT_UNIVERSAL));
addEntry(BAKED_EYES, new BakedEntry(TEX_EYES_BAKED,
"eyes", "27b1bc0f-979f-4b13-95fe-b981c2ba9788",
- 2, TEX_EYES_IRIS, TEX_EYES_ALPHA,
- 2, LLWearableType::WT_EYES, LLWearableType::WT_ALPHA));
+ 3, TEX_EYES_IRIS, TEX_EYES_TATTOO, TEX_EYES_ALPHA,
+ 3, LLWearableType::WT_EYES, LLWearableType::WT_UNIVERSAL, LLWearableType::WT_ALPHA));
addEntry(BAKED_SKIRT, new BakedEntry(TEX_SKIRT_BAKED,
"skirt", "03e7e8cb-1368-483b-b6f3-74850838ba63",
- 1, TEX_SKIRT,
- 1, LLWearableType::WT_SKIRT));
+ 2, TEX_SKIRT, TEX_SKIRT_TATTOO,
+ 2, LLWearableType::WT_SKIRT, LLWearableType::WT_UNIVERSAL ));
addEntry(BAKED_HAIR, new BakedEntry(TEX_HAIR_BAKED,
"hair", "a60e85a9-74e8-48d8-8a2d-8129f28d9b61",
- 2, TEX_HAIR, TEX_HAIR_ALPHA,
- 2, LLWearableType::WT_HAIR, LLWearableType::WT_ALPHA));
+ 3, TEX_HAIR, TEX_HAIR_TATTOO, TEX_HAIR_ALPHA,
+ 3, LLWearableType::WT_HAIR, LLWearableType::WT_UNIVERSAL, LLWearableType::WT_ALPHA));
+
+ addEntry(BAKED_LEFT_ARM, new BakedEntry(TEX_LEFT_ARM_BAKED,
+ "leftarm", "9f39febf-22d7-0087-79d1-e9e8c6c9ed19",
+ 1, TEX_LEFT_ARM_TATTOO,
+ 1, LLWearableType::WT_UNIVERSAL));
+
+ addEntry(BAKED_LEFT_LEG, new BakedEntry(TEX_LEFT_LEG_BAKED,
+ "leftleg", "054a7a58-8ed5-6386-0add-3b636fb28b78",
+ 1, TEX_LEFT_LEG_TATTOO,
+ 1, LLWearableType::WT_UNIVERSAL));
+
+ addEntry(BAKED_AUX1, new BakedEntry(TEX_AUX1_BAKED,
+ "aux1", "790c11be-b25c-c17e-b4d2-6a4ad786b752",
+ 1, TEX_AUX1_TATTOO,
+ 1, LLWearableType::WT_UNIVERSAL));
+
+ addEntry(BAKED_AUX2, new BakedEntry(TEX_AUX2_BAKED,
+ "aux2", "d78c478f-48c7-5928-5864-8d99fb1f521e",
+ 1, TEX_AUX2_TATTOO,
+ 1, LLWearableType::WT_UNIVERSAL));
+
+ addEntry(BAKED_AUX3, new BakedEntry(TEX_AUX3_BAKED,
+ "aux3", "6a95dd53-edd9-aac8-f6d3-27ed99f3c3eb",
+ 1, TEX_AUX3_TATTOO,
+ 1, LLWearableType::WT_UNIVERSAL));
}
LLAvatarAppearanceDictionary::MeshEntries::MeshEntries()
@@ -140,7 +186,7 @@ LLAvatarAppearanceDictionary::~LLAvatarAppearanceDictionary()
// map it to the baked texture.
void LLAvatarAppearanceDictionary::createAssociations()
{
- for (BakedTextures::const_iterator iter = mBakedTextures.begin(); iter != mBakedTextures.end(); iter++)
+ for (BakedTextures::const_iterator iter = mBakedTextures.begin(); iter != mBakedTextures.end(); ++iter)
{
const EBakedTextureIndex baked_index = (iter->first);
const BakedEntry *dict = (iter->second);
@@ -149,7 +195,7 @@ void LLAvatarAppearanceDictionary::createAssociations()
// with this baked texture index.
for (texture_vec_t::const_iterator local_texture_iter = dict->mLocalTextures.begin();
local_texture_iter != dict->mLocalTextures.end();
- local_texture_iter++)
+ ++local_texture_iter)
{
const ETextureIndex local_texture_index = (ETextureIndex) *local_texture_iter;
mTextures[local_texture_index]->mIsUsedByBakedTexture = true;
@@ -212,6 +258,7 @@ LLAvatarAppearanceDictionary::BakedEntry::BakedEntry(ETextureIndex tex_index,
LLWearableType::EType t = (LLWearableType::EType)va_arg(argp,int);
mWearables.push_back(t);
}
+ va_end(argp);
}
// static
@@ -221,7 +268,7 @@ ETextureIndex LLAvatarAppearanceDictionary::bakedToLocalTextureIndex(EBakedTextu
}
// static
-EBakedTextureIndex LLAvatarAppearanceDictionary::findBakedByRegionName(std::string name)
+EBakedTextureIndex LLAvatarAppearanceDictionary::findBakedByRegionName(const std::string& name)
{
U8 index = 0;
while (index < BAKED_NUM_INDICES)
@@ -239,7 +286,7 @@ EBakedTextureIndex LLAvatarAppearanceDictionary::findBakedByRegionName(std::stri
}
// static
-EBakedTextureIndex LLAvatarAppearanceDictionary::findBakedByImageName(std::string name)
+EBakedTextureIndex LLAvatarAppearanceDictionary::findBakedByImageName(const std::string& name)
{
U8 index = 0;
while (index < BAKED_NUM_INDICES)
@@ -266,3 +313,112 @@ LLWearableType::EType LLAvatarAppearanceDictionary::getTEWearableType(ETextureIn
return getInstance()->getTexture(index)->mWearableType;
}
+// static
+BOOL LLAvatarAppearanceDictionary::isBakedImageId(const LLUUID& id)
+{
+ if ((id == IMG_USE_BAKED_EYES) || (id == IMG_USE_BAKED_HAIR) || (id == IMG_USE_BAKED_HEAD) || (id == IMG_USE_BAKED_LOWER) || (id == IMG_USE_BAKED_SKIRT) || (id == IMG_USE_BAKED_UPPER)
+ || (id == IMG_USE_BAKED_LEFTARM) || (id == IMG_USE_BAKED_LEFTLEG) || (id == IMG_USE_BAKED_AUX1) || (id == IMG_USE_BAKED_AUX2) || (id == IMG_USE_BAKED_AUX3) )
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+// static
+EBakedTextureIndex LLAvatarAppearanceDictionary::assetIdToBakedTextureIndex(const LLUUID& id)
+{
+ if (id == IMG_USE_BAKED_EYES)
+ {
+ return BAKED_EYES;
+ }
+ else if (id == IMG_USE_BAKED_HAIR)
+ {
+ return BAKED_HAIR;
+ }
+ else if (id == IMG_USE_BAKED_HEAD)
+ {
+ return BAKED_HEAD;
+ }
+ else if (id == IMG_USE_BAKED_LOWER)
+ {
+ return BAKED_LOWER;
+ }
+ else if (id == IMG_USE_BAKED_SKIRT)
+ {
+ return BAKED_SKIRT;
+ }
+ else if (id == IMG_USE_BAKED_UPPER)
+ {
+ return BAKED_UPPER;
+ }
+ else if (id == IMG_USE_BAKED_LEFTARM)
+ {
+ return BAKED_LEFT_ARM;
+ }
+ else if (id == IMG_USE_BAKED_LEFTLEG)
+ {
+ return BAKED_LEFT_LEG;
+ }
+ else if (id == IMG_USE_BAKED_AUX1)
+ {
+ return BAKED_AUX1;
+ }
+ else if (id == IMG_USE_BAKED_AUX2)
+ {
+ return BAKED_AUX2;
+ }
+ else if (id == IMG_USE_BAKED_AUX3)
+ {
+ return BAKED_AUX3;
+ }
+
+ return BAKED_NUM_INDICES;
+}
+
+//static
+LLUUID LLAvatarAppearanceDictionary::localTextureIndexToMagicId(ETextureIndex t)
+{
+ LLUUID id = LLUUID::null;
+
+ switch (t)
+ {
+ case LLAvatarAppearanceDefines::TEX_HEAD_BAKED:
+ id = IMG_USE_BAKED_HEAD;
+ break;
+ case LLAvatarAppearanceDefines::TEX_UPPER_BAKED:
+ id = IMG_USE_BAKED_UPPER;
+ break;
+ case LLAvatarAppearanceDefines::TEX_LOWER_BAKED:
+ id = IMG_USE_BAKED_LOWER;
+ break;
+ case LLAvatarAppearanceDefines::TEX_EYES_BAKED:
+ id = IMG_USE_BAKED_EYES;
+ break;
+ case LLAvatarAppearanceDefines::TEX_SKIRT_BAKED:
+ id = IMG_USE_BAKED_SKIRT;
+ break;
+ case LLAvatarAppearanceDefines::TEX_HAIR_BAKED:
+ id = IMG_USE_BAKED_HAIR;
+ break;
+ case LLAvatarAppearanceDefines::TEX_LEFT_ARM_BAKED:
+ id = IMG_USE_BAKED_LEFTARM;
+ break;
+ case LLAvatarAppearanceDefines::TEX_LEFT_LEG_BAKED:
+ id = IMG_USE_BAKED_LEFTLEG;
+ break;
+ case LLAvatarAppearanceDefines::TEX_AUX1_BAKED:
+ id = IMG_USE_BAKED_AUX1;
+ break;
+ case LLAvatarAppearanceDefines::TEX_AUX2_BAKED:
+ id = IMG_USE_BAKED_AUX2;
+ break;
+ case LLAvatarAppearanceDefines::TEX_AUX3_BAKED:
+ id = IMG_USE_BAKED_AUX3;
+ break;
+ default:
+ break;
+ }
+
+ return id;
+}
diff --git a/indra/llappearance/llavatarappearancedefines.h b/indra/llappearance/llavatarappearancedefines.h
index 8a1d2c4707..444af9c050 100644
--- a/indra/llappearance/llavatarappearancedefines.h
+++ b/indra/llappearance/llavatarappearancedefines.h
@@ -1,3 +1,4 @@
+
/**
* @file llavatarappearancedefines.h
* @brief Various LLAvatarAppearance related definitions
@@ -78,6 +79,22 @@ enum ETextureIndex
TEX_HEAD_TATTOO,
TEX_UPPER_TATTOO,
TEX_LOWER_TATTOO,
+ TEX_HEAD_UNIVERSAL_TATTOO,
+ TEX_UPPER_UNIVERSAL_TATTOO,
+ TEX_LOWER_UNIVERSAL_TATTOO,
+ TEX_SKIRT_TATTOO,
+ TEX_HAIR_TATTOO,
+ TEX_EYES_TATTOO,
+ TEX_LEFT_ARM_TATTOO,
+ TEX_LEFT_LEG_TATTOO,
+ TEX_AUX1_TATTOO,
+ TEX_AUX2_TATTOO,
+ TEX_AUX3_TATTOO,
+ TEX_LEFT_ARM_BAKED, // Pre-composited
+ TEX_LEFT_LEG_BAKED, // Pre-composited
+ TEX_AUX1_BAKED, // Pre-composited
+ TEX_AUX2_BAKED, // Pre-composited
+ TEX_AUX3_BAKED, // Pre-composited
TEX_NUM_INDICES
};
@@ -89,6 +106,11 @@ enum EBakedTextureIndex
BAKED_EYES,
BAKED_SKIRT,
BAKED_HAIR,
+ BAKED_LEFT_ARM,
+ BAKED_LEFT_LEG,
+ BAKED_AUX1,
+ BAKED_AUX2,
+ BAKED_AUX3,
BAKED_NUM_INDICES
};
@@ -218,12 +240,15 @@ class LLAvatarAppearanceDictionary : public LLSingleton(*iter);
- if (!joint)
- continue;
-
- F32 jointLOD = joint->getLOD();
-
- if (found_lod || jointLOD == DEFAULT_AVATAR_JOINT_LOD)
- {
- // we've already found a joint to enable, so enable the rest as alternatives
- lod_changed |= joint->updateLOD(pixel_area, TRUE);
- }
- else
+ if (joint)
{
- if (pixel_area >= jointLOD || sDisableLOD)
+ F32 jointLOD = joint->getLOD();
+
+ if (found_lod || jointLOD == DEFAULT_AVATAR_JOINT_LOD)
{
+ // we've already found a joint to enable, so enable the rest as alternatives
lod_changed |= joint->updateLOD(pixel_area, TRUE);
- found_lod = TRUE;
}
else
{
- lod_changed |= joint->updateLOD(pixel_area, FALSE);
+ if (pixel_area >= jointLOD || sDisableLOD)
+ {
+ lod_changed |= joint->updateLOD(pixel_area, TRUE);
+ found_lod = TRUE;
+ }
+ else
+ {
+ lod_changed |= joint->updateLOD(pixel_area, FALSE);
+ }
}
}
}
@@ -232,7 +231,7 @@ void LLAvatarJoint::setMeshesToChildren()
{
removeAllChildren();
for (avatar_joint_mesh_list_t::iterator iter = mMeshParts.begin();
- iter != mMeshParts.end(); iter++)
+ iter != mMeshParts.end(); ++iter)
{
addChild((*iter));
}
diff --git a/indra/llappearance/llavatarjoint.h b/indra/llappearance/llavatarjoint.h
index e4da9bb9ad..95d5a124b8 100644
--- a/indra/llappearance/llavatarjoint.h
+++ b/indra/llappearance/llavatarjoint.h
@@ -52,7 +52,7 @@ class LLAvatarJoint :
virtual ~LLAvatarJoint();
// Gets the validity of this joint
- BOOL getValid() { return mValid; }
+ bool getValid() const { return mValid; }
// Sets the validity of this joint
virtual void setValid( BOOL valid, BOOL recursive=FALSE );
diff --git a/indra/llappearance/llavatarjointmesh.cpp b/indra/llappearance/llavatarjointmesh.cpp
index 4853a6670b..2cfcac4c18 100644
--- a/indra/llappearance/llavatarjointmesh.cpp
+++ b/indra/llappearance/llavatarjointmesh.cpp
@@ -57,6 +57,41 @@
#include "llmatrix4a.h"
+// Utility functions added with Bento to simplify handling of extra
+// spine joints, or other new joints internal to the original
+// skeleton, and unknown to the system avatar.
+
+//-----------------------------------------------------------------------------
+// getBaseSkeletonAncestor()
+//-----------------------------------------------------------------------------
+LLJoint *getBaseSkeletonAncestor(LLJoint* joint)
+{
+ LLJoint *ancestor = joint->getParent();
+ while (ancestor->getParent() && (ancestor->getSupport() != LLJoint::SUPPORT_BASE))
+ {
+ LL_DEBUGS("Avatar") << "skipping non-base ancestor " << ancestor->getName() << LL_ENDL;
+ ancestor = ancestor->getParent();
+ }
+ return ancestor;
+}
+
+//-----------------------------------------------------------------------------
+// totalSkinOffset()
+//-----------------------------------------------------------------------------
+LLVector3 totalSkinOffset(LLJoint *joint)
+{
+ LLVector3 totalOffset;
+ while (joint)
+ {
+ if (joint->getSupport() == LLJoint::SUPPORT_BASE)
+ {
+ totalOffset += joint->getSkinOffset();
+ }
+ joint = joint->getParent();
+ }
+ return totalOffset;
+}
+
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// LLAvatarJointMesh::LLSkinJoint
@@ -83,28 +118,24 @@ LLSkinJoint::~LLSkinJoint()
//-----------------------------------------------------------------------------
// LLSkinJoint::setupSkinJoint()
//-----------------------------------------------------------------------------
-void LLSkinJoint::setupSkinJoint( LLJoint *joint)
+BOOL LLSkinJoint::setupSkinJoint( LLJoint *joint)
{
- mRootToJointSkinOffset.clearVec();
- mRootToParentJointSkinOffset.clearVec();
-
// find the named joint
- if (!(mJoint = joint))
+ if (!(mJoint = dynamic_cast(joint)))
{
LL_INFOS() << "Can't find joint" << LL_ENDL;
- return;
+ return FALSE;
}
// compute the inverse root skin matrix
- do
- {
- mRootToJointSkinOffset -= joint->getSkinOffset();
- } while (joint = joint->getParent());
+ mRootToJointSkinOffset = totalSkinOffset(mJoint);
+ mRootToJointSkinOffset = -mRootToJointSkinOffset;
- mRootToParentJointSkinOffset = mRootToJointSkinOffset;
- mRootToParentJointSkinOffset += mJoint->getSkinOffset();
+ //mRootToParentJointSkinOffset = totalSkinOffset((LLAvatarJoint*)joint->getParent());
+ mRootToParentJointSkinOffset = totalSkinOffset(getBaseSkeletonAncestor(mJoint));
+ mRootToParentJointSkinOffset = -mRootToParentJointSkinOffset;
- return;
+ return TRUE;
}
@@ -313,9 +344,9 @@ void LLAvatarJointMesh::setMesh( LLPolyMesh *mesh )
if (!mMesh->isLOD())
{
setupJoint(getRoot());
+ LL_DEBUGS("Avatar") << getName() << " joint render entries: " << mMesh->mJointRenderData.size() << LL_ENDL;
}
- LL_DEBUGS() << "joint render entries: " << mMesh->mJointRenderData.size() << LL_ENDL;
}
//-----------------------------------------------------------------------------
@@ -323,10 +354,8 @@ void LLAvatarJointMesh::setMesh( LLPolyMesh *mesh )
//-----------------------------------------------------------------------------
void LLAvatarJointMesh::setupJoint(LLJoint* current_joint)
{
-// LL_INFOS() << "Mesh: " << getName() << LL_ENDL;
-
-// S32 joint_count = 0;
U32 sj;
+
for (sj=0; sjgetName() << " matches skinjoint " << sj << LL_ENDL;
// is the last joint in the array our parent?
- if(mMesh->mJointRenderData.size() && mMesh->mJointRenderData[mMesh->mJointRenderData.size() - 1]->mWorldMatrix == ¤t_joint->getParent()->getWorldMatrix())
+
+ std::vector &jrd = mMesh->mJointRenderData;
+
+ // SL-287 - need to update this so the results are the same if
+ // additional extended-skeleton joints lie between this joint
+ // and the original parent.
+ LLJoint *ancestor = getBaseSkeletonAncestor(current_joint);
+ if(jrd.size() && jrd.back()->mWorldMatrix == &ancestor->getWorldMatrix())
{
// ...then just add ourselves
LLJoint* jointp = js.mJoint;
- mMesh->mJointRenderData.push_back(new LLJointRenderData(&jointp->getWorldMatrix(), &js));
-// LL_INFOS() << "joint " << joint_count << js.mJoint->getName() << LL_ENDL;
-// joint_count++;
+ jrd.push_back(new LLJointRenderData(&jointp->getWorldMatrix(), &js));
+ LL_DEBUGS("Avatar") << "add joint[" << (jrd.size()-1) << "] = " << js.mJoint->getName() << LL_ENDL;
}
- // otherwise add our parent and ourselves
+ // otherwise add our ancestor and ourselves
else
{
- mMesh->mJointRenderData.push_back(new LLJointRenderData(¤t_joint->getParent()->getWorldMatrix(), NULL));
-// LL_INFOS() << "joint " << joint_count << current_joint->getParent()->getName() << LL_ENDL;
-// joint_count++;
- mMesh->mJointRenderData.push_back(new LLJointRenderData(¤t_joint->getWorldMatrix(), &js));
-// LL_INFOS() << "joint " << joint_count << current_joint->getName() << LL_ENDL;
-// joint_count++;
+ jrd.push_back(new LLJointRenderData(&ancestor->getWorldMatrix(), NULL));
+ LL_DEBUGS("Avatar") << "add2 ancestor joint[" << (jrd.size()-1) << "] = " << ancestor->getName() << LL_ENDL;
+ jrd.push_back(new LLJointRenderData(¤t_joint->getWorldMatrix(), &js));
+ LL_DEBUGS("Avatar") << "add2 joint[" << (jrd.size()-1) << "] = " << current_joint->getName() << LL_ENDL;
}
}
diff --git a/indra/llappearance/llavatarjointmesh.h b/indra/llappearance/llavatarjointmesh.h
index 5dece5972c..3ee647103d 100644
--- a/indra/llappearance/llavatarjointmesh.h
+++ b/indra/llappearance/llavatarjointmesh.h
@@ -49,7 +49,7 @@ class LLSkinJoint
public:
LLSkinJoint();
~LLSkinJoint();
- void setupSkinJoint( LLJoint *joint);
+ BOOL setupSkinJoint( LLJoint *joint);
LLJoint* mJoint;
LLVector3 mRootToJointSkinOffset;
@@ -124,6 +124,9 @@ class LLAvatarJointMesh : public virtual LLAvatarJoint
// Sets up joint matrix data for rendering
void setupJoint(LLJoint* current_joint);
+ // Render time method to upload batches of joint matrices
+ void uploadJointMatrices();
+
// Sets ID for picking
void setMeshID( S32 id ) {mMeshID = id;}
diff --git a/indra/llappearance/lldriverparam.cpp b/indra/llappearance/lldriverparam.cpp
index d7e3ce858f..cf16074472 100644
--- a/indra/llappearance/lldriverparam.cpp
+++ b/indra/llappearance/lldriverparam.cpp
@@ -102,7 +102,7 @@ void LLDriverParamInfo::toStream(std::ostream &out)
LLViewerVisualParamInfo::toStream(out);
out << "driver" << "\t";
out << mDrivenInfoList.size() << "\t";
- for (entry_info_list_t::iterator iter = mDrivenInfoList.begin(); iter != mDrivenInfoList.end(); iter++)
+ for (entry_info_list_t::iterator iter = mDrivenInfoList.begin(); iter != mDrivenInfoList.end(); ++iter)
{
LLDrivenEntryInfo driven = *iter;
out << driven.mDrivenID << "\t";
@@ -110,14 +110,26 @@ void LLDriverParamInfo::toStream(std::ostream &out)
out << std::endl;
- if(mDriverParam && mDriverParam->getAvatarAppearance()->isSelf() &&
- mDriverParam->getAvatarAppearance()->isValid())
+ // FIXME - this mDriverParam backlink makes no sense, because the
+ // LLDriverParamInfos are static objects - there's only one copy
+ // for each param type, so the backlink will just reference the
+ // corresponding param in the most recently created
+ // avatar. Apparently these toStream() methods are not currently
+ // used anywhere, so it's not an urgent problem.
+ LL_WARNS_ONCE() << "Invalid usage of mDriverParam." << LL_ENDL;
+
+ if (!mDriverParam)
+ return;
+ const auto& avatar_appearance = mDriverParam->getAvatarAppearance();
+
+ if(avatar_appearance->isSelf() &&
+ avatar_appearance->isValid())
{
- for (entry_info_list_t::iterator iter = mDrivenInfoList.begin(); iter != mDrivenInfoList.end(); iter++)
+ for (entry_info_list_t::iterator iter = mDrivenInfoList.begin(); iter != mDrivenInfoList.end(); ++iter)
{
LLDrivenEntryInfo driven = *iter;
LLViewerVisualParam *param =
- (LLViewerVisualParam*)mDriverParam->getAvatarAppearance()->getVisualParam(driven.mDrivenID);
+ (LLViewerVisualParam*) avatar_appearance->getVisualParam(driven.mDrivenID);
if (param)
{
param->getInfo()->toStream(out);
@@ -140,7 +152,7 @@ void LLDriverParamInfo::toStream(std::ostream &out)
else
{
LL_WARNS() << "could not get parameter " << driven.mDrivenID << " from avatar "
- << mDriverParam->getAvatarAppearance()
+ << avatar_appearance
<< " for driver parameter " << getID() << LL_ENDL;
}
out << std::endl;
@@ -224,7 +236,7 @@ void LLDriverParam::setWeight(F32 weight, bool upload_bake)
//-------|----|-------|----|-------> driver
// | min1 max1 max2 min2
- for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
+ for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); ++iter )
{
LLDrivenEntry* driven = &(*iter);
LLDrivenEntryInfo* info = driven->mInfo;
@@ -297,7 +309,7 @@ void LLDriverParam::setWeight(F32 weight, bool upload_bake)
F32 LLDriverParam::getTotalDistortion()
{
F32 sum = 0.f;
- for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
+ for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); ++iter )
{
LLDrivenEntry* driven = &(*iter);
sum += driven->mParam->getTotalDistortion();
@@ -312,7 +324,7 @@ const LLVector4a &LLDriverParam::getAvgDistortion()
LLVector4a sum;
sum.clear();
S32 count = 0;
- for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
+ for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); ++iter )
{
LLDrivenEntry* driven = &(*iter);
sum.add(driven->mParam->getAvgDistortion());
@@ -327,7 +339,7 @@ const LLVector4a &LLDriverParam::getAvgDistortion()
F32 LLDriverParam::getMaxDistortion()
{
F32 max = 0.f;
- for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
+ for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); ++iter )
{
LLDrivenEntry* driven = &(*iter);
F32 param_max = driven->mParam->getMaxDistortion();
@@ -345,7 +357,7 @@ LLVector4a LLDriverParam::getVertexDistortion(S32 index, LLPolyMesh *poly_mesh)
{
LLVector4a sum;
sum.clear();
- for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
+ for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); ++iter )
{
LLDrivenEntry* driven = &(*iter);
sum.add(driven->mParam->getVertexDistortion( index, poly_mesh ));
@@ -357,7 +369,7 @@ const LLVector4a* LLDriverParam::getFirstDistortion(U32 *index, LLPolyMesh **pol
{
mCurrentDistortionParam = NULL;
const LLVector4a* v = NULL;
- for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
+ for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); ++iter )
{
LLDrivenEntry* driven = &(*iter);
v = driven->mParam->getFirstDistortion( index, poly_mesh );
@@ -383,7 +395,7 @@ const LLVector4a* LLDriverParam::getNextDistortion(U32 *index, LLPolyMesh **poly
entry_list_t::iterator iter;
// Set mDriven iteration to the right point
- for( iter = mDriven.begin(); iter != mDriven.end(); iter++ )
+ for( iter = mDriven.begin(); iter != mDriven.end(); ++iter )
{
driven = &(*iter);
if( driven->mParam == mCurrentDistortionParam )
@@ -404,7 +416,7 @@ const LLVector4a* LLDriverParam::getNextDistortion(U32 *index, LLPolyMesh **poly
{
// This param is finished, so start the next param. It might not have any
// distortions, though, so we have to loop to find the next param that does.
- for( iter++; iter != mDriven.end(); iter++ )
+ for( ++iter; iter != mDriven.end(); ++iter )
{
driven = &(*iter);
v = driven->mParam->getFirstDistortion( index, poly_mesh );
@@ -440,7 +452,7 @@ void LLDriverParam::setAnimationTarget( F32 target_value, bool upload_bake )
{
LLVisualParam::setAnimationTarget(target_value, upload_bake);
- for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
+ for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); ++iter )
{
LLDrivenEntry* driven = &(*iter);
F32 driven_weight = getDrivenWeight(driven, mTargetWeight);
@@ -458,7 +470,7 @@ void LLDriverParam::stopAnimating(bool upload_bake)
{
LLVisualParam::stopAnimating(upload_bake);
- for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
+ for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); ++iter )
{
LLDrivenEntry* driven = &(*iter);
driven->mParam->setAnimating(FALSE);
@@ -515,7 +527,7 @@ void LLDriverParam::updateCrossDrivenParams(LLWearableType::EType driven_type)
bool needs_update = (getWearableType()==driven_type);
// if the driver has a driven entry for the passed-in wearable type, we need to refresh the value
- for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
+ for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); ++iter )
{
LLDrivenEntry* driven = &(*iter);
if (driven && driven->mParam && driven->mParam->getCrossWearable() && driven->mParam->getWearableType() == driven_type)
diff --git a/indra/llappearance/lldriverparam.h b/indra/llappearance/lldriverparam.h
index ce6fa6345e..a7dec8acb3 100644
--- a/indra/llappearance/lldriverparam.h
+++ b/indra/llappearance/lldriverparam.h
@@ -29,6 +29,7 @@
#include "llviewervisualparam.h"
#include "llwearabletype.h"
+#include
class LLAvatarAppearance;
class LLDriverParam;
@@ -130,6 +131,10 @@ class LLDriverParam : public LLViewerVisualParam
S32 getDrivenParamsCount() const;
const LLViewerVisualParam* getDrivenParam(S32 index) const;
+ typedef std::vector entry_list_t;
+ entry_list_t& getDrivenList() { return mDriven; }
+ void setDrivenList(entry_list_t& driven_list) { mDriven = driven_list; }
+
protected:
LLDriverParam(const LLDriverParam& pOther);
F32 getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight);
@@ -137,7 +142,6 @@ class LLDriverParam : public LLViewerVisualParam
LL_ALIGN_16(LLVector4a mDefaultVec); // temp holder
- typedef std::vector entry_list_t;
entry_list_t mDriven;
LLViewerVisualParam* mCurrentDistortionParam;
// Backlink only; don't make this an LLPointer.
diff --git a/indra/llappearance/lllocaltextureobject.cpp b/indra/llappearance/lllocaltextureobject.cpp
index f49cf21512..f0a789c467 100644
--- a/indra/llappearance/lllocaltextureobject.cpp
+++ b/indra/llappearance/lllocaltextureobject.cpp
@@ -76,6 +76,7 @@ LLLocalTextureObject::LLLocalTextureObject(const LLLocalTextureObject& lto) :
LLLocalTextureObject::~LLLocalTextureObject()
{
+ delete_and_clear(mTexLayers);
}
LLGLTexture* LLLocalTextureObject::getImage() const
@@ -95,7 +96,7 @@ LLTexLayer* LLLocalTextureObject::getTexLayer(U32 index) const
LLTexLayer* LLLocalTextureObject::getTexLayer(const std::string &name)
{
- for( tex_layer_vec_t::iterator iter = mTexLayers.begin(); iter != mTexLayers.end(); iter++)
+ for( tex_layer_vec_t::iterator iter = mTexLayers.begin(); iter != mTexLayers.end(); ++iter)
{
LLTexLayer *layer = *iter;
if (layer->getName().compare(name) == 0)
@@ -196,7 +197,7 @@ BOOL LLLocalTextureObject::removeTexLayer(U32 index)
return TRUE;
}
-void LLLocalTextureObject::setID(LLUUID new_id)
+void LLLocalTextureObject::setID(const LLUUID& new_id)
{
mID = new_id;
}
diff --git a/indra/llappearance/lllocaltextureobject.h b/indra/llappearance/lllocaltextureobject.h
index 9b9f41fd19..699dbafcdc 100644
--- a/indra/llappearance/lllocaltextureobject.h
+++ b/indra/llappearance/lllocaltextureobject.h
@@ -61,7 +61,7 @@ class LLLocalTextureObject
BOOL addTexLayer(LLTexLayerTemplate *new_tex_layer, LLWearable *wearable);
BOOL removeTexLayer(U32 index);
- void setID(LLUUID new_id);
+ void setID(const LLUUID& new_id);
void setDiscard(S32 new_discard);
void setBakedReady(BOOL ready);
diff --git a/indra/llappearance/llpolymesh.cpp b/indra/llappearance/llpolymesh.cpp
index b9e70fd83f..529755819a 100644
--- a/indra/llappearance/llpolymesh.cpp
+++ b/indra/llappearance/llpolymesh.cpp
@@ -161,7 +161,7 @@ void LLPolyMeshSharedData::freeMeshData()
// mVertFaceMap.deleteAllData();
}
-// compate_int is used by the qsort function to sort the index array
+// compare_int is used by the qsort function to sort the index array
S32 compare_int(const void *a, const void *b);
//-----------------------------------------------------------------------------
@@ -307,7 +307,11 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName )
//----------------------------------------------------------------
// File Header (seek past it)
//----------------------------------------------------------------
- fseek(fp, 24, SEEK_SET);
+ if (fseek(fp, 24, SEEK_SET) != 0)
+ {
+ LL_ERRS() << "can't seek past header from " << fileName << LL_ENDL;
+ return FALSE;
+ }
//----------------------------------------------------------------
// HasWeights
@@ -605,7 +609,7 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName )
//-------------------------------------------------------------------------
char morphName[64+1];
morphName[sizeof(morphName)-1] = '\0'; // ensure nul-termination
- while(fread(&morphName, sizeof(char), 64, fp) == 64)
+ while(fread(morphName, sizeof(char), 64, fp) == 64)
{
if (!strcmp(morphName, "End Morphs"))
{
@@ -629,10 +633,6 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName )
mMorphData.insert(clone_morph_param_cleavage(morph_data,
.75f,
"Breast_Physics_LeftRight_Driven"));
- }
-
- if (!strcmp(morphName, "Breast_Female_Cleavage"))
- {
mMorphData.insert(clone_morph_param_duplicate(morph_data,
"Breast_Physics_InOut_Driven"));
}
@@ -668,9 +668,6 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName )
mMorphData.insert(clone_morph_param_direction(morph_data,
LLVector3(0,0,0.05f),
"Butt_Physics_UpDown_Driven"));
- }
- if (!strcmp(morphName, "Small_Butt"))
- {
mMorphData.insert(clone_morph_param_direction(morph_data,
LLVector3(0,0.03f,0),
"Butt_Physics_LeftRight_Driven"));
diff --git a/indra/llappearance/llpolymorph.cpp b/indra/llappearance/llpolymorph.cpp
index 873169cba3..626940b190 100644
--- a/indra/llappearance/llpolymorph.cpp
+++ b/indra/llappearance/llpolymorph.cpp
@@ -109,7 +109,7 @@ LLPolyMorphData::~LLPolyMorphData()
BOOL LLPolyMorphData::loadBinary(LLFILE *fp, LLPolyMeshSharedData *mesh)
{
S32 numVertices;
- S32 numRead;
+ size_t numRead; //
numRead = fread(&numVertices, sizeof(S32), 1, fp);
llendianswizzle(&numVertices, sizeof(S32), 1);
@@ -680,8 +680,8 @@ BOOL LLPolyMorphTarget::setInfo(LLPolyMorphTargetInfo* info)
if (!mMorphData)
{
const std::string driven_tag = "_Driven";
- U32 pos = morph_param_name.find(driven_tag);
- if (pos > 0)
+ size_t pos = morph_param_name.find(driven_tag);
+ if (pos != std::string::npos)
{
morph_param_name = morph_param_name.substr(0,pos);
mMorphData = mMesh->getMorphData(morph_param_name);
@@ -835,7 +835,7 @@ F32 LLPolyMorphTarget::getMaxDistortion()
//-----------------------------------------------------------------------------
// apply()
//-----------------------------------------------------------------------------
-static LLFastTimer::DeclareTimer FTM_APPLY_MORPH_TARGET("Apply Morph");
+static LLTrace::BlockTimerStatHandle FTM_APPLY_MORPH_TARGET("Apply Morph");
void LLPolyMorphTarget::apply( ESex avatar_sex )
{
@@ -844,7 +844,7 @@ void LLPolyMorphTarget::apply( ESex avatar_sex )
return;
}
- LLFastTimer t(FTM_APPLY_MORPH_TARGET);
+ LL_RECORD_BLOCK_TIME(FTM_APPLY_MORPH_TARGET);
mLastSex = avatar_sex;
@@ -937,7 +937,7 @@ void LLPolyMorphTarget::apply( ESex avatar_sex )
}
// now apply volume changes
- for( volume_list_t::iterator iter = mVolumeMorphs.begin(); iter != mVolumeMorphs.end(); iter++ )
+ for( volume_list_t::iterator iter = mVolumeMorphs.begin(); iter != mVolumeMorphs.end(); ++iter )
{
LLPolyVolumeMorph* volume_morph = &(*iter);
LLVector3 scale_delta = volume_morph->mScale * delta_weight;
@@ -1027,6 +1027,20 @@ void LLPolyMorphTarget::applyMask(U8 *maskTextureData, S32 width, S32 height, S3
apply(mLastSex);
}
+void LLPolyMorphTarget::applyVolumeChanges(F32 delta_weight)
+{
+ // now apply volume changes
+ for( volume_list_t::iterator iter = mVolumeMorphs.begin(); iter != mVolumeMorphs.end(); ++iter )
+ {
+ LLPolyVolumeMorph* volume_morph = &(*iter);
+ LLVector3 scale_delta = volume_morph->mScale * delta_weight;
+ LLVector3 pos_delta = volume_morph->mPos * delta_weight;
+
+ volume_morph->mVolume->setScale(volume_morph->mVolume->getScale() + scale_delta);
+ // SL-315
+ volume_morph->mVolume->setPosition(volume_morph->mVolume->getPosition() + pos_delta);
+ }
+}
//-----------------------------------------------------------------------------
// LLPolyVertexMask()
diff --git a/indra/llappearance/llpolymorph.h b/indra/llappearance/llpolymorph.h
index aa1591bf7f..7c6dca9ec6 100644
--- a/indra/llappearance/llpolymorph.h
+++ b/indra/llappearance/llpolymorph.h
@@ -186,6 +186,7 @@ class LLPolyMorphTarget : public LLViewerVisualParam
void applyMask(U8 *maskData, S32 width, S32 height, S32 num_components, BOOL invert);
void addPendingMorphMask() { mNumMorphMasksPending++; }
+ void applyVolumeChanges(F32 delta_weight); // SL-315 - for resetSkeleton()
void* operator new(size_t size)
{
diff --git a/indra/llappearance/llpolyskeletaldistortion.cpp b/indra/llappearance/llpolyskeletaldistortion.cpp
index 4bfef71a14..a9debf4b47 100644
--- a/indra/llappearance/llpolyskeletaldistortion.cpp
+++ b/indra/llappearance/llpolyskeletaldistortion.cpp
@@ -141,54 +141,58 @@ LLPolySkeletalDistortion::~LLPolySkeletalDistortion()
BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info)
{
llassert(mInfo == NULL);
- if (info->mID < 0)
- return FALSE;
- mInfo = info;
- mID = info->mID;
- setWeight(getDefaultWeight());
-
- LLPolySkeletalDistortionInfo::bone_info_list_t::iterator iter;
- for (iter = getInfo()->mBoneInfoList.begin(); iter != getInfo()->mBoneInfoList.end(); iter++)
+ if (info->mID < 0)
+ {
+ return FALSE;
+ }
+ mInfo = info;
+ mID = info->mID;
+ setWeight(getDefaultWeight());
+
+ LLPolySkeletalDistortionInfo::bone_info_list_t::iterator iter;
+ for (iter = getInfo()->mBoneInfoList.begin(); iter != getInfo()->mBoneInfoList.end(); ++iter)
+ {
+ LLPolySkeletalBoneInfo *bone_info = &(*iter);
+ LLJoint* joint = mAvatar->getJoint(bone_info->mBoneName);
+ if (!joint)
+ {
+ // There's no point continuing after this error - means
+ // that either the skeleton or lad file is broken.
+ LL_WARNS() << "Joint " << bone_info->mBoneName << " not found." << LL_ENDL;
+ return FALSE;
+ }
+
+ if (mJointScales.find(joint) != mJointScales.end())
+ {
+ LL_WARNS() << "Scale deformation already supplied for joint " << joint->getName() << "." << LL_ENDL;
+ }
+
+ // store it
+ mJointScales[joint] = bone_info->mScaleDeformation;
+
+ // apply to children that need to inherit it
+ for (LLJoint::child_list_t::iterator iter = joint->mChildren.begin();
+ iter != joint->mChildren.end(); ++iter)
+ {
+ LLAvatarJoint* child_joint = dynamic_cast(*iter);
+ if (child_joint && child_joint->inheritScale())
+ {
+ LLVector3 childDeformation = LLVector3(child_joint->getScale());
+ childDeformation.scaleVec(bone_info->mScaleDeformation);
+ mJointScales[child_joint] = childDeformation;
+ }
+ }
+
+ if (bone_info->mHasPositionDeformation)
{
- LLPolySkeletalBoneInfo *bone_info = &(*iter);
- LLJoint* joint = mAvatar->getJoint(bone_info->mBoneName);
- if (!joint)
- {
- LL_WARNS() << "Joint " << bone_info->mBoneName << " not found." << LL_ENDL;
- continue;
- }
-
- if (mJointScales.find(joint) != mJointScales.end())
- {
- LL_WARNS() << "Scale deformation already supplied for joint " << joint->getName() << "." << LL_ENDL;
- }
-
- // store it
- mJointScales[joint] = bone_info->mScaleDeformation;
-
- // apply to children that need to inherit it
- for (LLJoint::child_list_t::iterator iter = joint->mChildren.begin();
- iter != joint->mChildren.end(); ++iter)
- {
- LLAvatarJoint* child_joint = dynamic_cast(*iter);
- if (child_joint && child_joint->inheritScale())
- {
- LLVector3 childDeformation = LLVector3(child_joint->getScale());
- childDeformation.scaleVec(bone_info->mScaleDeformation);
- mJointScales[child_joint] = childDeformation;
- }
- }
-
- if (bone_info->mHasPositionDeformation)
- {
- if (mJointOffsets.find(joint) != mJointOffsets.end())
- {
- LL_WARNS() << "Offset deformation already supplied for joint " << joint->getName() << "." << LL_ENDL;
- }
- mJointOffsets[joint] = bone_info->mPositionDeformation;
- }
+ if (mJointOffsets.find(joint) != mJointOffsets.end())
+ {
+ LL_WARNS() << "Offset deformation already supplied for joint " << joint->getName() << "." << LL_ENDL;
+ }
+ mJointOffsets[joint] = bone_info->mPositionDeformation;
}
- return TRUE;
+ }
+ return TRUE;
}
/*virtual*/ LLViewerVisualParam* LLPolySkeletalDistortion::cloneParam(LLWearable* wearable) const
@@ -199,44 +203,55 @@ BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info)
//-----------------------------------------------------------------------------
// apply()
//-----------------------------------------------------------------------------
-static LLFastTimer::DeclareTimer FTM_POLYSKELETAL_DISTORTION_APPLY("Skeletal Distortion");
+static LLTrace::BlockTimerStatHandle FTM_POLYSKELETAL_DISTORTION_APPLY("Skeletal Distortion");
void LLPolySkeletalDistortion::apply( ESex avatar_sex )
{
- LLFastTimer t(FTM_POLYSKELETAL_DISTORTION_APPLY);
+ LL_RECORD_BLOCK_TIME(FTM_POLYSKELETAL_DISTORTION_APPLY);
- F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight();
+ F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight();
- LLJoint* joint;
- joint_vec_map_t::iterator iter;
+ LLJoint* joint;
+ joint_vec_map_t::iterator iter;
for (iter = mJointScales.begin();
iter != mJointScales.end();
- iter++)
+ ++iter)
{
joint = iter->first;
LLVector3 newScale = joint->getScale();
- LLVector3 scaleDelta = iter->second;
- newScale = newScale + (effective_weight * scaleDelta) - (mLastWeight * scaleDelta);
- joint->setScale(newScale);
+ LLVector3 scaleDelta = iter->second;
+ LLVector3 offset = (effective_weight - mLastWeight) * scaleDelta;
+ newScale = newScale + offset;
+ //An aspect of attached mesh objects (which contain joint offsets) that need to be cleaned up when detached
+ // needed?
+ // joint->storeScaleForReset( newScale );
+
+ // BENTO for detailed stack tracing of params.
+ // std::stringstream ostr;
+ // ostr << "LLPolySkeletalDistortion::apply, id " << getID() << " " << getName() << " effective wt " << effective_weight << " last wt " << mLastWeight << " scaleDelta " << scaleDelta << " offset " << offset;
+
+ joint->setScale(newScale, true);
}
- for (iter = mJointOffsets.begin();
- iter != mJointOffsets.end();
- iter++)
- {
- joint = iter->first;
- LLVector3 newPosition = joint->getPosition();
- LLVector3 positionDelta = iter->second;
+ for (iter = mJointOffsets.begin();
+ iter != mJointOffsets.end();
+ ++iter)
+ {
+ joint = iter->first;
+ LLVector3 newPosition = joint->getPosition();
+ LLVector3 positionDelta = iter->second;
newPosition = newPosition + (effective_weight * positionDelta) - (mLastWeight * positionDelta);
- joint->setPosition(newPosition);
- }
+ // SL-315
+ bool allow_attachment_pos_overrides = true;
+ joint->setPosition(newPosition, allow_attachment_pos_overrides);
+ }
- if (mLastWeight != mCurWeight && !mIsAnimating)
+ if (mLastWeight != effective_weight && !mIsAnimating)
{
mAvatar->setSkeletonSerialNum(mAvatar->getSkeletonSerialNum() + 1);
}
- mLastWeight = mCurWeight;
+ mLastWeight = effective_weight;
}
diff --git a/indra/llappearance/lltexglobalcolor.cpp b/indra/llappearance/lltexglobalcolor.cpp
index a241df8e42..0df6981536 100644
--- a/indra/llappearance/lltexglobalcolor.cpp
+++ b/indra/llappearance/lltexglobalcolor.cpp
@@ -57,7 +57,7 @@ BOOL LLTexGlobalColor::setInfo(LLTexGlobalColorInfo *info)
mParamGlobalColorList.reserve(mInfo->mParamColorInfoList.size());
for (param_color_info_list_t::iterator iter = mInfo->mParamColorInfoList.begin();
iter != mInfo->mParamColorInfoList.end();
- iter++)
+ ++iter)
{
LLTexParamGlobalColor* param_color = new LLTexParamGlobalColor(this);
if (!param_color->setInfo(*iter, TRUE))
@@ -135,6 +135,7 @@ LLTexGlobalColorInfo::LLTexGlobalColorInfo()
LLTexGlobalColorInfo::~LLTexGlobalColorInfo()
{
for_each(mParamColorInfoList.begin(), mParamColorInfoList.end(), DeletePointer());
+ mParamColorInfoList.clear();
}
BOOL LLTexGlobalColorInfo::parseXml(LLXmlTreeNode* node)
diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp
index b0f922b950..83a72eeb1c 100644
--- a/indra/llappearance/lltexlayer.cpp
+++ b/indra/llappearance/lltexlayer.cpp
@@ -256,7 +256,7 @@ void LLTexLayerSetInfo::createVisualParams(LLAvatarAppearance *appearance)
//layer_info_list_t mLayerInfoList;
for (layer_info_list_t::iterator layer_iter = mLayerInfoList.begin();
layer_iter != mLayerInfoList.end();
- layer_iter++)
+ ++layer_iter)
{
LLTexLayerInfo *layer_info = *layer_iter;
layer_info->createVisualParams(appearance);
@@ -299,7 +299,7 @@ BOOL LLTexLayerSet::setInfo(const LLTexLayerSetInfo *info)
mLayerList.reserve(info->mLayerInfoList.size());
for (LLTexLayerSetInfo::layer_info_list_t::const_iterator iter = info->mLayerInfoList.begin();
iter != info->mLayerInfoList.end();
- iter++)
+ ++iter)
{
LLTexLayerInterface *layer = NULL;
if ( (*iter)->isUserSettable() )
@@ -358,12 +358,12 @@ BOOL LLTexLayerSet::parseData(LLXmlTreeNode* node)
void LLTexLayerSet::deleteCaches()
{
- for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ )
+ for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); ++iter )
{
LLTexLayerInterface* layer = *iter;
layer->deleteCaches();
}
- for (layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); iter++)
+ for (layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); ++iter)
{
LLTexLayerInterface* layer = *iter;
layer->deleteCaches();
@@ -378,7 +378,7 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height )
if (mMaskLayerList.size() > 0)
{
- for (layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); iter++)
+ for (layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); ++iter)
{
LLTexLayerInterface* layer = *iter;
if (layer->isInvisibleAlphaMask())
@@ -397,7 +397,7 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height )
// clear buffer area to ensure we don't pick up UI elements
{
gGL.flush();
- LLGLDisable no_alpha(GL_ALPHA_TEST);
+ LLGLDisable no_alpha;
if (use_shaders)
{
gAlphaMaskProgram.setMinimumAlpha(0.0f);
@@ -417,7 +417,7 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height )
if (mIsVisible)
{
// composite color layers
- for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ )
+ for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); ++iter )
{
LLTexLayerInterface* layer = *iter;
if (layer->getRenderPass() == LLTexLayer::RP_COLOR)
@@ -437,7 +437,7 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height )
gGL.flush();
gGL.setSceneBlendType(LLRender::BT_REPLACE);
- LLGLDisable no_alpha(GL_ALPHA_TEST);
+ LLGLDisable no_alpha;
if (use_shaders)
{
gAlphaMaskProgram.setMinimumAlpha(0.f);
@@ -521,13 +521,13 @@ const LLTexLayerSetBuffer* LLTexLayerSet::getComposite() const
return mComposite;
}
-static LLFastTimer::DeclareTimer FTM_GATHER_MORPH_MASK_ALPHA("gatherMorphMaskAlpha");
+static LLTrace::BlockTimerStatHandle FTM_GATHER_MORPH_MASK_ALPHA("gatherMorphMaskAlpha");
void LLTexLayerSet::gatherMorphMaskAlpha(U8 *data, S32 origin_x, S32 origin_y, S32 width, S32 height)
{
- LLFastTimer t(FTM_GATHER_MORPH_MASK_ALPHA);
+ LL_RECORD_BLOCK_TIME(FTM_GATHER_MORPH_MASK_ALPHA);
memset(data, 255, width * height);
- for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ )
+ for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); ++iter )
{
LLTexLayerInterface* layer = *iter;
layer->gatherAlphaMasks(data, origin_x, origin_y, width, height);
@@ -537,10 +537,10 @@ void LLTexLayerSet::gatherMorphMaskAlpha(U8 *data, S32 origin_x, S32 origin_y, S
renderAlphaMaskTextures(origin_x, origin_y, width, height, true);
}
-static LLFastTimer::DeclareTimer FTM_RENDER_ALPHA_MASK_TEXTURES("renderAlphaMaskTextures");
+static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_MASK_TEXTURES("renderAlphaMaskTextures");
void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, bool forceClear)
{
- LLFastTimer t(FTM_RENDER_ALPHA_MASK_TEXTURES);
+ LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK_TEXTURES);
const LLTexLayerSetInfo *info = getInfo();
bool use_shaders = LLGLSLShader::sNoFixedFunction;
@@ -568,7 +568,7 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height,
{
// Set the alpha channel to one (clean up after previous blending)
gGL.flush();
- LLGLDisable no_alpha(GL_ALPHA_TEST);
+ LLGLDisable no_alpha;
if (use_shaders)
{
gAlphaMaskProgram.setMinimumAlpha(0.f);
@@ -591,7 +591,7 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height,
{
gGL.setSceneBlendType(LLRender::BT_MULT_ALPHA);
gGL.getTexUnit(0)->setTextureBlendType( LLTexUnit::TB_REPLACE );
- for (layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); iter++)
+ for (layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); ++iter)
{
LLTexLayerInterface* layer = *iter;
gGL.flush();
@@ -615,7 +615,7 @@ void LLTexLayerSet::applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_
BOOL LLTexLayerSet::isMorphValid() const
{
- for(layer_list_t::const_iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ )
+ for(layer_list_t::const_iterator iter = mLayerList.begin(); iter != mLayerList.end(); ++iter )
{
const LLTexLayerInterface* layer = *iter;
if (layer && !layer->isMorphValid())
@@ -628,7 +628,7 @@ BOOL LLTexLayerSet::isMorphValid() const
void LLTexLayerSet::invalidateMorphMasks()
{
- for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ )
+ for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); ++iter )
{
LLTexLayerInterface* layer = *iter;
if (layer)
@@ -727,7 +727,7 @@ BOOL LLTexLayerInfo::parseXml(LLXmlTreeNode* node)
mLocalTexture = TEX_NUM_INDICES;
for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin();
iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end();
- iter++)
+ ++iter)
{
const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = iter->second;
if (local_texture_name == texture_dict->mName)
@@ -801,7 +801,7 @@ BOOL LLTexLayerInfo::createVisualParams(LLAvatarAppearance *appearance)
BOOL success = TRUE;
for (param_color_info_list_t::iterator color_info_iter = mParamColorInfoList.begin();
color_info_iter != mParamColorInfoList.end();
- color_info_iter++)
+ ++color_info_iter)
{
LLTexLayerParamColorInfo * color_info = *color_info_iter;
LLTexLayerParamColor* param_color = new LLTexLayerParamColor(appearance);
@@ -815,7 +815,7 @@ BOOL LLTexLayerInfo::createVisualParams(LLAvatarAppearance *appearance)
for (param_alpha_info_list_t::iterator alpha_info_iter = mParamAlphaInfoList.begin();
alpha_info_iter != mParamAlphaInfoList.end();
- alpha_info_iter++)
+ ++alpha_info_iter)
{
LLTexLayerParamAlphaInfo * alpha_info = *alpha_info_iter;
LLTexLayerParamAlpha* param_alpha = new LLTexLayerParamAlpha(appearance);
@@ -862,7 +862,7 @@ BOOL LLTexLayerInterface::setInfo(const LLTexLayerInfo *info, LLWearable* wearab
mParamColorList.reserve(mInfo->mParamColorInfoList.size());
for (param_color_info_list_t::const_iterator iter = mInfo->mParamColorInfoList.begin();
iter != mInfo->mParamColorInfoList.end();
- iter++)
+ ++iter)
{
LLTexLayerParamColor* param_color;
if (!wearable)
@@ -889,7 +889,7 @@ BOOL LLTexLayerInterface::setInfo(const LLTexLayerInfo *info, LLWearable* wearab
mParamAlphaList.reserve(mInfo->mParamAlphaInfoList.size());
for (param_alpha_info_list_t::const_iterator iter = mInfo->mParamAlphaInfoList.begin();
iter != mInfo->mParamAlphaInfoList.end();
- iter++)
+ ++iter)
{
LLTexLayerParamAlpha* param_alpha;
if (!wearable)
@@ -940,7 +940,7 @@ LLWearableType::EType LLTexLayerInterface::getWearableType() const
param_color_list_t::const_iterator color_iter = mParamColorList.begin();
param_alpha_list_t::const_iterator alpha_iter = mParamAlphaList.begin();
- for (; color_iter != mParamColorList.end(); color_iter++)
+ for (; color_iter != mParamColorList.end(); ++color_iter)
{
LLTexLayerParamColor* param = *color_iter;
if (param)
@@ -957,7 +957,7 @@ LLWearableType::EType LLTexLayerInterface::getWearableType() const
}
}
- for (; alpha_iter != mParamAlphaList.end(); alpha_iter++)
+ for (; alpha_iter != mParamAlphaList.end(); ++alpha_iter)
{
LLTexLayerParamAlpha* param = *alpha_iter;
if (param)
@@ -1059,7 +1059,7 @@ LLTexLayer::~LLTexLayer()
//std::for_each(mParamColorList.begin(), mParamColorList.end(), DeletePointer());
for( alpha_cache_t::iterator iter = mAlphaCache.begin();
- iter != mAlphaCache.end(); iter++ )
+ iter != mAlphaCache.end(); ++iter )
{
U8* alpha_data = iter->second;
delete [] alpha_data;
@@ -1086,7 +1086,7 @@ BOOL LLTexLayer::setInfo(const LLTexLayerInfo* info, LLWearable* wearable )
void LLTexLayer::calculateTexLayerColor(const param_color_list_t ¶m_list, LLColor4 &net_color)
{
for (param_color_list_t::const_iterator iter = param_list.begin();
- iter != param_list.end(); iter++)
+ iter != param_list.end(); ++iter)
{
const LLTexLayerParamColor* param = *iter;
LLColor4 param_net = param->getNetColor();
@@ -1114,7 +1114,7 @@ void LLTexLayer::calculateTexLayerColor(const param_color_list_t ¶m_list, LL
{
// Only need to delete caches for alpha params. Color params don't hold extra memory
for (param_alpha_list_t::iterator iter = mParamAlphaList.begin();
- iter != mParamAlphaList.end(); iter++ )
+ iter != mParamAlphaList.end(); ++iter )
{
LLTexLayerParamAlpha* param = *iter;
param->deleteCaches();
@@ -1123,14 +1123,11 @@ void LLTexLayer::calculateTexLayerColor(const param_color_list_t ¶m_list, LL
BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height)
{
- LLGLEnable color_mat(GL_COLOR_MATERIAL);
+ LLGLEnable color_mat;
// *TODO: Is this correct?
//gPipeline.disableLights();
stop_glerror();
- if (!LLGLSLShader::sNoFixedFunction)
- {
- glDisable(GL_LIGHTING);
- }
+ LLGLDisable no_lighting(!LLGLSLShader::sNoFixedFunction);
stop_glerror();
bool use_shaders = LLGLSLShader::sNoFixedFunction;
@@ -1217,7 +1214,7 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height)
if( tex )
{
bool no_alpha_test = getInfo()->mWriteAllChannels;
- LLGLDisable alpha_test(no_alpha_test ? GL_ALPHA_TEST : 0);
+ LLGLDisable alpha_test(no_alpha_test);
if (no_alpha_test)
{
if (use_shaders)
@@ -1273,7 +1270,7 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height)
getInfo()->mStaticImageFileName.empty() &&
color_specified )
{
- LLGLDisable no_alpha(GL_ALPHA_TEST);
+ LLGLDisable no_alpha;
if (use_shaders)
{
gAlphaMaskProgram.setMinimumAlpha(0.000f);
@@ -1309,7 +1306,7 @@ const U8* LLTexLayer::getAlphaData() const
const LLUUID& uuid = getUUID();
alpha_mask_crc.update((U8*)(&uuid.mData), UUID_BYTES);
- for (param_alpha_list_t::const_iterator iter = mParamAlphaList.begin(); iter != mParamAlphaList.end(); iter++)
+ for (param_alpha_list_t::const_iterator iter = mParamAlphaList.begin(); iter != mParamAlphaList.end(); ++iter)
{
const LLTexLayerParamAlpha* param = *iter;
// MULTI-WEARABLE: verify visual parameters used here
@@ -1430,7 +1427,7 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height)
addAlphaMask(data, originX, originY, width, height);
}
-static LLFastTimer::DeclareTimer FTM_RENDER_MORPH_MASKS("renderMorphMasks");
+static LLTrace::BlockTimerStatHandle FTM_RENDER_MORPH_MASKS("renderMorphMasks");
void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLColor4 &layer_color, bool force_render)
{
if (!force_render && !hasMorph())
@@ -1438,7 +1435,7 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
LL_DEBUGS() << "skipping renderMorphMasks for " << getUUID() << LL_ENDL;
return;
}
- LLFastTimer t(FTM_RENDER_MORPH_MASKS);
+ LL_RECORD_BLOCK_TIME(FTM_RENDER_MORPH_MASKS);
BOOL success = TRUE;
llassert( !mParamAlphaList.empty() );
@@ -1456,7 +1453,7 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
// Note: if the first param is a mulitply, multiply against the current buffer's alpha
if( !first_param || !first_param->getMultiplyBlend() )
{
- LLGLDisable no_alpha(GL_ALPHA_TEST);
+ LLGLDisable no_alpha;
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
// Clear the alpha
@@ -1470,7 +1467,7 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
// Accumulate alphas
LLGLSNoAlphaTest gls_no_alpha_test;
gGL.color4f( 1.f, 1.f, 1.f, 1.f );
- for (param_alpha_list_t::iterator iter = mParamAlphaList.begin(); iter != mParamAlphaList.end(); iter++)
+ for (param_alpha_list_t::iterator iter = mParamAlphaList.begin(); iter != mParamAlphaList.end(); ++iter)
{
LLTexLayerParamAlpha* param = *iter;
success &= param->render( x, y, width, height );
@@ -1528,7 +1525,7 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
// Note: we're still using gGL.blendFunc( GL_DST_ALPHA, GL_ZERO );
if ( !is_approx_equal(layer_color.mV[VW], 1.f) )
{
- LLGLDisable no_alpha(GL_ALPHA_TEST);
+ LLGLDisable no_alpha;
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
gGL.color4fv(layer_color.mV);
gl_rect_2d_simple( width, height );
@@ -1549,7 +1546,7 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
const LLUUID& uuid = getUUID();
alpha_mask_crc.update((U8*)(&uuid.mData), UUID_BYTES);
- for (param_alpha_list_t::const_iterator iter = mParamAlphaList.begin(); iter != mParamAlphaList.end(); iter++)
+ for (param_alpha_list_t::const_iterator iter = mParamAlphaList.begin(); iter != mParamAlphaList.end(); ++iter)
{
const LLTexLayerParamAlpha* param = *iter;
F32 param_weight = param->getWeight();
@@ -1557,13 +1554,13 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
}
U32 cache_index = alpha_mask_crc.getCRC();
- U8* alpha_data = NULL;//get_if_there(mAlphaCache,cache_index,(U8*)NULL);
+ U8* alpha_data = NULL;
// We believe we need to generate morph masks, do not assume that the cached version is accurate.
// We can get bad morph masks during login, on minimize, and occasional gl errors.
// We should only be doing this when we believe something has changed with respect to the user's appearance.
- //if (!alpha_data)
{
- // clear out a slot if we have filled our cache
+ LL_DEBUGS("Avatar") << "gl alpha cache of morph mask not found, doing readback: " << getName() << LL_ENDL;
+ // clear out a slot if we have filled our cache
S32 max_cache_entries = getTexLayerSet()->getAvatarAppearance()->isSelf() ? 4 : 1;
while ((S32)mAlphaCache.size() >= max_cache_entries)
{
@@ -1573,8 +1570,12 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
mAlphaCache.erase(iter2);
}
alpha_data = new U8[width * height];
+ U8* pixels_tmp = new U8[width * height * 4];
+ glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels_tmp);
+ for (int i = 0; i < width * height; ++i)
+ alpha_data[i] = pixels_tmp[i * 4 + 3];
+ delete[] pixels_tmp;
mAlphaCache[cache_index] = alpha_data;
- glReadPixels(x, y, width, height, GL_ALPHA, GL_UNSIGNED_BYTE, alpha_data);
}
getTexLayerSet()->getAvatarAppearance()->dirtyMesh();
@@ -1584,10 +1585,10 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
}
}
-static LLFastTimer::DeclareTimer FTM_ADD_ALPHA_MASK("addAlphaMask");
+static LLTrace::BlockTimerStatHandle FTM_ADD_ALPHA_MASK("addAlphaMask");
void LLTexLayer::addAlphaMask(U8 *data, S32 originX, S32 originY, S32 width, S32 height)
{
- LLFastTimer t(FTM_ADD_ALPHA_MASK);
+ LL_RECORD_BLOCK_TIME(FTM_ADD_ALPHA_MASK);
S32 size = width * height;
const U8* alphaData = getAlphaData();
if (!alphaData && hasAlphaParams())
@@ -1740,7 +1741,7 @@ LLTexLayer* LLTexLayerTemplate::getLayer(U32 i) const
BOOL success = TRUE;
updateWearableCache();
- for (wearable_cache_t::const_iterator iter = mWearableCache.begin(); iter!= mWearableCache.end(); iter++)
+ for (wearable_cache_t::const_iterator iter = mWearableCache.begin(); iter!= mWearableCache.end(); ++iter)
{
LLWearable* wearable = NULL;
LLLocalTextureObject *lto = NULL;
@@ -1783,13 +1784,11 @@ LLTexLayer* LLTexLayerTemplate::getLayer(U32 i) const
/*virtual*/ void LLTexLayerTemplate::gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height)
{
U32 num_wearables = updateWearableCache();
- for (U32 i = 0; i < num_wearables; i++)
+ U32 i = num_wearables - 1; // For rendering morph masks, we only want to use the top wearable
+ LLTexLayer *layer = getLayer(i);
+ if (layer)
{
- LLTexLayer *layer = getLayer(i);
- if (layer)
- {
- layer->addAlphaMask(data, originX, originY, width, height);
- }
+ layer->addAlphaMask(data, originX, originY, width, height);
}
}
@@ -1844,7 +1843,7 @@ LLTexLayer* LLTexLayerTemplate::getLayer(U32 i) const
//-----------------------------------------------------------------------------
LLTexLayerInterface* LLTexLayerSet::findLayerByName(const std::string& name)
{
- for (layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ )
+ for (layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); ++iter )
{
LLTexLayerInterface* layer = *iter;
if (layer->getName() == name)
@@ -1852,7 +1851,7 @@ LLTexLayerInterface* LLTexLayerSet::findLayerByName(const std::string& name)
return layer;
}
}
- for (layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); iter++ )
+ for (layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); ++iter )
{
LLTexLayerInterface* layer = *iter;
if (layer->getName() == name)
@@ -1866,7 +1865,7 @@ LLTexLayerInterface* LLTexLayerSet::findLayerByName(const std::string& name)
void LLTexLayerSet::cloneTemplates(LLLocalTextureObject *lto, LLAvatarAppearanceDefines::ETextureIndex tex_index, LLWearable *wearable)
{
// initialize all texlayers with this texture type for this LTO
- for( LLTexLayerSet::layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ )
+ for( LLTexLayerSet::layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); ++iter )
{
LLTexLayerTemplate* layer = (LLTexLayerTemplate*)*iter;
if (layer->getInfo()->getLocalTexture() == (S32) tex_index)
@@ -1874,7 +1873,7 @@ void LLTexLayerSet::cloneTemplates(LLLocalTextureObject *lto, LLAvatarAppearance
lto->addTexLayer(layer, wearable);
}
}
- for( LLTexLayerSet::layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); iter++ )
+ for( LLTexLayerSet::layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); ++iter )
{
LLTexLayerTemplate* layer = (LLTexLayerTemplate*)*iter;
if (layer->getInfo()->getLocalTexture() == (S32) tex_index)
@@ -1930,10 +1929,10 @@ void LLTexLayerStaticImageList::deleteCachedImages()
// Returns an LLImageTGA that contains the encoded data from a tga file named file_name.
// Caches the result to speed identical subsequent requests.
-static LLFastTimer::DeclareTimer FTM_LOAD_STATIC_TGA("getImageTGA");
+static LLTrace::BlockTimerStatHandle FTM_LOAD_STATIC_TGA("getImageTGA");
LLImageTGA* LLTexLayerStaticImageList::getImageTGA(const std::string& file_name)
{
- LLFastTimer t(FTM_LOAD_STATIC_TGA);
+ LL_RECORD_BLOCK_TIME(FTM_LOAD_STATIC_TGA);
const char *namekey = mImageNames.addString(file_name);
image_tga_map_t::const_iterator iter = mStaticImageListTGA.find(namekey);
if( iter != mStaticImageListTGA.end() )
@@ -1960,10 +1959,10 @@ LLImageTGA* LLTexLayerStaticImageList::getImageTGA(const std::string& file_name)
// Returns a GL Image (without a backing ImageRaw) that contains the decoded data from a tga file named file_name.
// Caches the result to speed identical subsequent requests.
-static LLFastTimer::DeclareTimer FTM_LOAD_STATIC_TEXTURE("getTexture");
+static LLTrace::BlockTimerStatHandle FTM_LOAD_STATIC_TEXTURE("getTexture");
LLGLTexture* LLTexLayerStaticImageList::getTexture(const std::string& file_name, BOOL is_mask)
{
- LLFastTimer t(FTM_LOAD_STATIC_TEXTURE);
+ LL_RECORD_BLOCK_TIME(FTM_LOAD_STATIC_TEXTURE);
LLPointer tex;
const char *namekey = mImageNames.addString(file_name);
@@ -1991,7 +1990,7 @@ LLGLTexture* LLTexLayerStaticImageList::getTexture(const std::string& file_name,
image_raw->copyUnscaledAlphaMask(alpha_image_raw, LLColor4U::black);
}
- tex->createGLTexture(0, image_raw, 0, TRUE, LLGLTexture::LOCAL);
+ tex->createGLTexture(0, image_raw, nullptr, TRUE, LLGLTexture::LOCAL);
gGL.getTexUnit(0)->bind(tex);
tex->setAddressMode(LLTexUnit::TAM_CLAMP);
@@ -2010,10 +2009,10 @@ LLGLTexture* LLTexLayerStaticImageList::getTexture(const std::string& file_name,
// Reads a .tga file, decodes it, and puts the decoded data in image_raw.
// Returns TRUE if successful.
-static LLFastTimer::DeclareTimer FTM_LOAD_IMAGE_RAW("loadImageRaw");
+static LLTrace::BlockTimerStatHandle FTM_LOAD_IMAGE_RAW("loadImageRaw");
BOOL LLTexLayerStaticImageList::loadImageRaw(const std::string& file_name, LLImageRaw* image_raw)
{
- LLFastTimer t(FTM_LOAD_IMAGE_RAW);
+ LL_RECORD_BLOCK_TIME(FTM_LOAD_IMAGE_RAW);
BOOL success = FALSE;
std::string path;
path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,file_name);
diff --git a/indra/llappearance/lltexlayerparams.cpp b/indra/llappearance/lltexlayerparams.cpp
index 42cb163a52..7f3f486ca3 100644
--- a/indra/llappearance/lltexlayerparams.cpp
+++ b/indra/llappearance/lltexlayerparams.cpp
@@ -103,7 +103,7 @@ void LLTexLayerParamAlpha::getCacheByteCount(S32* gl_bytes)
*gl_bytes = 0;
for (param_alpha_ptr_list_t::iterator iter = sInstances.begin();
- iter != sInstances.end(); iter++)
+ iter != sInstances.end(); ++iter)
{
LLTexLayerParamAlpha* instance = *iter;
LLGLTexture* tex = instance->mCachedProcessedTexture;
@@ -260,10 +260,10 @@ BOOL LLTexLayerParamAlpha::getSkip() const
}
-static LLFastTimer::DeclareTimer FTM_TEX_LAYER_PARAM_ALPHA("alpha render");
+static LLTrace::BlockTimerStatHandle FTM_TEX_LAYER_PARAM_ALPHA("alpha render");
BOOL LLTexLayerParamAlpha::render(S32 x, S32 y, S32 width, S32 height)
{
- LLFastTimer t(FTM_TEX_LAYER_PARAM_ALPHA);
+ LL_RECORD_BLOCK_TIME(FTM_TEX_LAYER_PARAM_ALPHA);
BOOL success = TRUE;
if (!mTexLayer)
@@ -363,7 +363,7 @@ BOOL LLTexLayerParamAlpha::render(S32 x, S32 y, S32 width, S32 height)
}
else
{
- LLGLDisable no_alpha(GL_ALPHA_TEST);
+ LLGLDisable no_alpha;
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
gGL.color4f(0.f, 0.f, 0.f, effective_weight);
gl_rect_2d_simple(width, height);
@@ -491,7 +491,7 @@ void LLTexLayerParamColor::setWeight(F32 weight, bool upload_bake)
{
mCurWeight = new_weight;
- const LLTexLayerParamColorInfo *info = (LLTexLayerParamColorInfo *)getInfo();
+ const LLTexLayerParamColorInfo *info = (LLTexLayerParamColorInfo *)getInfo();
if (info->mNumColors <= 0)
{
diff --git a/indra/llappearance/llviewervisualparam.cpp b/indra/llappearance/llviewervisualparam.cpp
index 9e5deb07d4..61e81ff586 100644
--- a/indra/llappearance/llviewervisualparam.cpp
+++ b/indra/llappearance/llviewervisualparam.cpp
@@ -76,7 +76,7 @@ BOOL LLViewerVisualParamInfo::parseXml(LLXmlTreeNode *node)
static LLStdStringHandle edit_group_string = LLXmlTree::addAttributeString("edit_group");
if (!node->getFastAttributeString( edit_group_string, mEditGroup))
{
- mEditGroup = "";
+ mEditGroup.clear();
}
static LLStdStringHandle cross_wearable_string = LLXmlTree::addAttributeString("cross_wearable");
diff --git a/indra/llappearance/llwearable.cpp b/indra/llappearance/llwearable.cpp
index 45962d898a..31edbc67dc 100644
--- a/indra/llappearance/llwearable.cpp
+++ b/indra/llappearance/llwearable.cpp
@@ -86,10 +86,10 @@ LLAssetType::EType LLWearable::getAssetType() const
return LLWearableType::getAssetType(mType);
}
-BOOL LLWearable::exportFile(LLFILE* fp) const
+BOOL LLWearable::exportFile(const std::string& filename) const
{
- llofstream ofs(fp);
- return exportStream(ofs);
+ llofstream ofs(filename.c_str(), std::ios_base::out | std::ios_base::trunc | std::ios_base::binary);
+ return ofs.is_open() && exportStream(ofs);
}
// virtual
@@ -105,13 +105,13 @@ BOOL LLWearable::exportStream( std::ostream& output_stream ) const
output_stream << mDescription << "\n";
// permissions
- if( !mPermissions.exportStream( output_stream ) )
+ if( !mPermissions.exportLegacyStream( output_stream ) )
{
return FALSE;
}
// sale info
- if( !mSaleInfo.exportStream( output_stream ) )
+ if( !mSaleInfo.exportLegacyStream( output_stream ) )
{
return FALSE;
}
@@ -169,9 +169,9 @@ void LLWearable::createVisualParams(LLAvatarAppearance *avatarp)
// need this line to disambiguate between versions of LLCharacter::getVisualParam()
LLVisualParam*(LLAvatarAppearance::*param_function)(S32)const = &LLAvatarAppearance::getVisualParam;
param->resetDrivenParams();
- if(!param->linkDrivenParams(boost::bind(wearable_function,(LLWearable*)this, _1), false))
+ if (!param->linkDrivenParams(std::bind(wearable_function,(LLWearable*)this, std::placeholders::_1), false))
{
- if( !param->linkDrivenParams(boost::bind(param_function,avatarp,_1 ), true))
+ if (!param->linkDrivenParams(std::bind(param_function,avatarp, std::placeholders::_1 ), true))
{
LL_WARNS() << "could not link driven params for wearable " << getName() << " id: " << param->getID() << LL_ENDL;
continue;
@@ -184,7 +184,7 @@ void LLWearable::createLayers(S32 te, LLAvatarAppearance *avatarp)
{
LLTexLayerSet *layer_set = NULL;
const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearanceDictionary::getInstance()->getTexture((ETextureIndex)te);
- if (texture_dict->mIsUsedByBakedTexture)
+ if (texture_dict && texture_dict->mIsUsedByBakedTexture)
{
const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex;
@@ -193,18 +193,19 @@ void LLWearable::createLayers(S32 te, LLAvatarAppearance *avatarp)
if (layer_set)
{
- layer_set->cloneTemplates(mTEMap[te], (ETextureIndex)te, this);
+ layer_set->cloneTemplates(mTEMap[te], (ETextureIndex)te, this);
}
else
{
- LL_ERRS() << "could not find layerset for LTO in wearable!" << LL_ENDL;
+ LL_WARNS() << "could not find layerset for LTO in wearable!" << LL_ENDL;
}
}
-LLWearable::EImportResult LLWearable::importFile(LLFILE* fp, LLAvatarAppearance* avatarp )
+LLWearable::EImportResult LLWearable::importFile(const std::string& filename,
+ LLAvatarAppearance* avatarp )
{
- llifstream ifs(fp);
- return importStream(ifs, avatarp);
+ llifstream ifs(filename.c_str(), std::ios_base::in | std::ios_base::binary);
+ return (! ifs.is_open())? FAILURE : importStream(ifs, avatarp);
}
// virtual
@@ -287,7 +288,7 @@ LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream,
LL_WARNS() << "Bad Wearable asset: missing valid permissions" << LL_ENDL;
return LLWearable::FAILURE;
}
- if( !mPermissions.importStream( input_stream ) )
+ if( !mPermissions.importLegacyStream( input_stream ) )
{
return LLWearable::FAILURE;
}
@@ -312,7 +313,7 @@ LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream,
// up the vast majority of the tasks.
BOOL has_perm_mask = FALSE;
U32 perm_mask = 0;
- if( !mSaleInfo.importStream(input_stream, has_perm_mask, perm_mask) )
+ if( !mSaleInfo.importLegacyStream(input_stream, has_perm_mask, perm_mask) )
{
return LLWearable::FAILURE;
}
@@ -437,6 +438,12 @@ LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream,
return LLWearable::FAILURE;
}
+ if (te >= ETextureIndex::TEX_NUM_INDICES) //createLayers() converts to ETextureIndex
+ {
+ LL_WARNS() << "Bad Wearable asset: bad texture index: " << te << LL_ENDL;
+ return LLWearable::FAILURE;
+ }
+
if( !LLUUID::validate( uuid_buffer ) )
{
LL_WARNS() << "Bad Wearable asset: bad texture uuid: "
diff --git a/indra/llappearance/llwearable.h b/indra/llappearance/llwearable.h
index 3ffcc7516b..d9527b9e9c 100644
--- a/indra/llappearance/llwearable.h
+++ b/indra/llappearance/llwearable.h
@@ -82,8 +82,8 @@ class LLWearable
SUCCESS,
BAD_HEADER
};
- BOOL exportFile(LLFILE* file) const;
- EImportResult importFile(LLFILE* file, LLAvatarAppearance* avatarp );
+ BOOL exportFile(const std::string& filename) const;
+ EImportResult importFile(const std::string& filename, LLAvatarAppearance* avatarp );
virtual BOOL exportStream( std::ostream& output_stream ) const;
virtual EImportResult importStream( std::istream& input_stream, LLAvatarAppearance* avatarp );
diff --git a/indra/llappearance/llwearabledata.cpp b/indra/llappearance/llwearabledata.cpp
index 24c011d6fb..0e18ec1868 100644
--- a/indra/llappearance/llwearabledata.cpp
+++ b/indra/llappearance/llwearabledata.cpp
@@ -47,7 +47,6 @@ using namespace LLAvatarAppearanceDefines;
LLWearable* LLWearableData::getWearable(const LLWearableType::EType type, U32 index)
{
- //llassert_always(index == 0);
wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type);
if (wearable_iter == mWearableDatas.end())
{
@@ -66,7 +65,6 @@ LLWearable* LLWearableData::getWearable(const LLWearableType::EType type, U32 in
void LLWearableData::setWearable(const LLWearableType::EType type, U32 index, LLWearable *wearable)
{
- //llassert_always(index == 0);
LLWearable *old_wearable = getWearable(type,index);
if (!old_wearable)
{
@@ -178,8 +176,9 @@ bool LLWearableData::swapWearables(const LLWearableType::EType type, U32 index_a
}
wearableentry_vec_t& wearable_vec = wearable_iter->second;
- if (0 > index_a || index_a >= wearable_vec.size()) return false;
- if (0 > index_b || index_b >= wearable_vec.size()) return false;
+ // removed 0 > index_a and index_b comparisions - can never be true
+ if (index_a >= wearable_vec.size()) return false;
+ if (index_b >= wearable_vec.size()) return false;
LLWearable* wearable = wearable_vec[index_a];
wearable_vec[index_a] = wearable_vec[index_b];
diff --git a/indra/llappearance/llwearabledata.h b/indra/llappearance/llwearabledata.h
index 2cf5585e04..b83ba9a565 100644
--- a/indra/llappearance/llwearabledata.h
+++ b/indra/llappearance/llwearabledata.h
@@ -105,7 +105,7 @@ class LLWearableData
//Why this weird structure? LLWearableType::WT_COUNT small and known, therefore it's more efficient to make an array of vectors, indexed
//by wearable type. This allows O(1) lookups. This structure simply lets us plug in this optimization without touching any code elsewhere.
- typedef boost::array,LLWearableType::WT_COUNT> wearable_array_t;
+ typedef std::array, LLWearableType::WT_COUNT> wearable_array_t;
struct wearableentry_map_t : public wearable_array_t
{
wearableentry_map_t()
diff --git a/indra/llappearance/llwearabletype.cpp b/indra/llappearance/llwearabletype.cpp
index 8ad8b09bd6..b14107f9ea 100644
--- a/indra/llappearance/llwearabletype.cpp
+++ b/indra/llappearance/llwearabletype.cpp
@@ -29,17 +29,17 @@
#include "llinventorytype.h"
#include "llinventorydefines.h"
-static LLTranslationBridge* sTrans = NULL;
+static LLTranslationBridge::ptr_t sTrans = NULL;
// static
-void LLWearableType::initClass(LLTranslationBridge* trans)
+void LLWearableType::initClass(LLTranslationBridge::ptr_t &trans)
{
sTrans = trans;
}
void LLWearableType::cleanupClass()
{
- delete sTrans;
+ sTrans.reset();
}
struct WearableEntry : public LLDictionaryEntry
@@ -53,8 +53,7 @@ struct WearableEntry : public LLDictionaryEntry
LLDictionaryEntry(name),
mAssetType(assetType),
mDefaultNewName(default_new_name),
- //*TODO:Translate
- mLabel(/*sTrans->getString*/(name)),
+ mLabel(sTrans->getString(name)),
mIconName(iconName),
mDisableCameraSwitch(disable_camera_switch),
mAllowMultiwear(allow_multiwear)
@@ -99,11 +98,12 @@ LLWearableDictionary::LLWearableDictionary()
addEntry(LLWearableType::WT_SKIRT, new WearableEntry("skirt", "New Skirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SKIRT, FALSE, TRUE));
addEntry(LLWearableType::WT_ALPHA, new WearableEntry("alpha", "New Alpha", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_ALPHA, FALSE, TRUE));
addEntry(LLWearableType::WT_TATTOO, new WearableEntry("tattoo", "New Tattoo", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_TATTOO, FALSE, TRUE));
+ addEntry(LLWearableType::WT_UNIVERSAL, new WearableEntry("universal", "New Universal", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNIVERSAL, FALSE, TRUE));
-// addEntry(LLWearableType::WT_PHYSICS, new WearableEntry("physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PHYSICS, TRUE, TRUE));
// [SL:KB] - Patch: Appearance-Misc | Checked: 2011-05-29 (Catznip-2.6)
addEntry(LLWearableType::WT_PHYSICS, new WearableEntry("physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PHYSICS, TRUE, FALSE));
// [/SL:KB]
+// addEntry(LLWearableType::WT_PHYSICS, new WearableEntry("physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PHYSICS, TRUE, TRUE));
addEntry(LLWearableType::WT_UNKNOWN, new WearableEntry("unknown", "Clothing", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNKNOWN, FALSE, TRUE));
addEntry(LLWearableType::WT_INVALID, new WearableEntry("invalid", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryType::ICONNAME_NONE, FALSE, FALSE));
@@ -184,6 +184,6 @@ BOOL LLWearableType::getAllowMultiwear(LLWearableType::EType type)
// static
LLWearableType::EType LLWearableType::inventoryFlagsToWearableType(U32 flags)
{
- return (LLWearableType::EType)(flags & LLInventoryItemFlags::II_FLAGS_WEARABLES_MASK);
+ return (LLWearableType::EType)(flags & LLInventoryItemFlags::II_FLAGS_SUBTYPE_MASK);
}
diff --git a/indra/llappearance/llwearabletype.h b/indra/llappearance/llwearabletype.h
index 26c9fc230a..ec946d5ad3 100644
--- a/indra/llappearance/llwearabletype.h
+++ b/indra/llappearance/llwearabletype.h
@@ -31,16 +31,7 @@
#include "lldictionary.h"
#include "llinventorytype.h"
#include "llsingleton.h"
-
-class LLTranslationBridge
-{
-public:
- // clang needs this to be happy
- virtual ~LLTranslationBridge() {}
-
- virtual std::string getString(const std::string &xml_desc) = 0;
-};
-
+#include "llinvtranslationbrdg.h"
class LLWearableType
{
@@ -63,16 +54,18 @@ class LLWearableType
WT_ALPHA = 13,
WT_TATTOO = 14,
WT_PHYSICS = 15,
- WT_UNKNOWN = 16, // Singu note: used for corrupt wearables that do not have their type set in the inventory database.
+ WT_UNIVERSAL = 16,
+ WT_UNKNOWN = 17, // Singu note: used for corrupt wearables that do not have their type set in the inventory database.
// While all the above values are serialized and stored in the database, this value is local only:
- // When a new item with value 16 is added by upstream, just increase this value to 17 (and WT_COUNT to 18).
- WT_COUNT = 17,
+ // When a new item with value 17 is added by upstream, just increase this value to 18 (and WT_COUNT to 19).
+ // Keep WT_UNKNOWN and WT_COUNT in sync with llinventory.cpp
+ WT_COUNT = 18,
WT_INVALID = 255,
WT_NONE = -1,
};
- static void initClass(LLTranslationBridge* trans); // initializes static members
+ static void initClass(LLTranslationBridge::ptr_t &trans); // initializes static members
static void cleanupClass(); // initializes static members
static const std::string& getTypeName(EType type);
diff --git a/indra/llaudio/CMakeLists.txt b/indra/llaudio/CMakeLists.txt
index 25970a99a6..92aa14ddc7 100644
--- a/indra/llaudio/CMakeLists.txt
+++ b/indra/llaudio/CMakeLists.txt
@@ -3,24 +3,13 @@
project(llaudio)
include(00-Common)
-include(Audio)
-include(LLAudio)
-if (FMODSTUDIO)
- include(FMODSTUDIO)
-endif (FMODSTUDIO)
-if (FMODEX)
- include(FMODEX)
-endif (FMODEX)
+include(FMODSTUDIO)
include(OPENAL)
include(LLCommon)
include(LLMath)
include(LLMessage)
include(LLVFS)
-if (FMOD)
- include_directories(${FMOD_INCLUDE_DIR})
-endif(FMOD)
-
include_directories(
${LLAUDIO_INCLUDE_DIRS}
${LLCOMMON_INCLUDE_DIRS}
@@ -31,7 +20,7 @@ include_directories(
${VORBISENC_INCLUDE_DIRS}
${VORBISFILE_INCLUDE_DIRS}
${VORBIS_INCLUDE_DIRS}
- ${OPENAL_INCLUDE_DIRS}
+ ${OPENAL_LIB_INCLUDE_DIRS}
${FREEAULT_LIB_INCLUDE_DIRS}
)
@@ -54,7 +43,10 @@ set(llaudio_HEADER_FILES
llwindgen.h
)
-if (FMODSTUDIO)
+if (USE_FMODSTUDIO)
+ include_directories(
+ ${FMODSTUDIO_INCLUDE_DIR}
+ )
list(APPEND llaudio_SOURCE_FILES
llaudioengine_fmodstudio.cpp
lllistener_fmodstudio.cpp
@@ -66,21 +58,7 @@ if (FMODSTUDIO)
lllistener_fmodstudio.h
llstreamingaudio_fmodstudio.h
)
-endif (FMODSTUDIO)
-
-if (FMODEX)
- list(APPEND llaudio_SOURCE_FILES
- llaudioengine_fmodex.cpp
- lllistener_fmodex.cpp
- llstreamingaudio_fmodex.cpp
- )
-
- list(APPEND llaudio_HEADER_FILES
- llaudioengine_fmodex.h
- lllistener_fmodex.h
- llstreamingaudio_fmodex.h
- )
-endif (FMODEX)
+endif (USE_FMODSTUDIO)
if (OPENAL)
list(APPEND llaudio_SOURCE_FILES
@@ -100,5 +78,9 @@ set_source_files_properties(${llaudio_HEADER_FILES}
list(APPEND llaudio_SOURCE_FILES ${llaudio_HEADER_FILES})
add_library (llaudio ${llaudio_SOURCE_FILES})
-add_dependencies(llaudio prepare)
+target_link_libraries(
+ llaudio
+ PUBLIC
+ llcommon
+ )
diff --git a/indra/llaudio/llaudiodecodemgr.cpp b/indra/llaudio/llaudiodecodemgr.cpp
index 18635737b2..5f5696e376 100644
--- a/indra/llaudio/llaudiodecodemgr.cpp
+++ b/indra/llaudio/llaudiodecodemgr.cpp
@@ -33,7 +33,6 @@
#include "llaudiodecodemgr.h"
-#include "llvorbisdecode.h"
#include "llaudioengine.h"
#include "lllfsthread.h"
#include "llvfile.h"
@@ -43,10 +42,12 @@
#include "llassetstorage.h"
#include "llrefcount.h"
+#include "llvorbisencode.h"
+
#include "vorbis/codec.h"
#include "vorbis/vorbisfile.h"
-#include "llvorbisencode.h"
-#include //VS2010
+#include
+#include
extern LLAudioEngine *gAudiop;
@@ -120,7 +121,7 @@ size_t vfs_read(void *ptr, size_t size, size_t nmemb, void *datasource)
}
}
-int vfs_seek(void *datasource, ogg_int64_t offset, int whence)
+S32 vfs_seek(void *datasource, ogg_int64_t offset, S32 whence)
{
LLVFile *file = (LLVFile *)datasource;
@@ -142,7 +143,7 @@ int vfs_seek(void *datasource, ogg_int64_t offset, int whence)
origin = -1;
break;
default:
- LL_ERRS() << "Invalid whence argument to vfs_seek" << LL_ENDL;
+ LL_ERRS("AudioEngine") << "Invalid whence argument to vfs_seek" << LL_ENDL;
return -1;
}
@@ -156,7 +157,7 @@ int vfs_seek(void *datasource, ogg_int64_t offset, int whence)
}
}
-int vfs_close (void *datasource)
+S32 vfs_close (void *datasource)
{
LLVFile *file = (LLVFile *)datasource;
delete file;
@@ -196,25 +197,25 @@ BOOL LLVorbisDecodeState::initDecode()
vfs_callbacks.close_func = vfs_close;
vfs_callbacks.tell_func = vfs_tell;
- //LL_INFOS() << "Initing decode from vfile: " << mUUID << LL_ENDL;
+ LL_DEBUGS("AudioEngine") << "Initing decode from vfile: " << mUUID << LL_ENDL;
mInFilep = new LLVFile(gVFS, mUUID, LLAssetType::AT_SOUND);
if (!mInFilep || !mInFilep->getSize())
{
- LL_WARNS() << "unable to open vorbis source vfile for reading" << LL_ENDL;
+ LL_WARNS("AudioEngine") << "unable to open vorbis source vfile for reading" << LL_ENDL;
delete mInFilep;
mInFilep = NULL;
return FALSE;
}
- int r = ov_open_callbacks(mInFilep, &mVF, NULL, 0, vfs_callbacks);
+ S32 r = ov_open_callbacks(mInFilep, &mVF, NULL, 0, vfs_callbacks);
if(r < 0)
{
- LL_WARNS() << r << " Input to vorbis decode does not appear to be an Ogg bitstream: " << mUUID << LL_ENDL;
+ LL_WARNS("AudioEngine") << r << " Input to vorbis decode does not appear to be an Ogg bitstream: " << mUUID << LL_ENDL;
return(FALSE);
}
- S32 sample_count = ov_pcm_total(&mVF, -1);
+ S32 sample_count = (S32)ov_pcm_total(&mVF, -1);
size_t size_guess = (size_t)sample_count;
vorbis_info* vi = ov_info(&mVF, -1);
size_guess *= (vi? vi->channels : 1);
@@ -228,13 +229,13 @@ BOOL LLVorbisDecodeState::initDecode()
if( vi->channels < 1 || vi->channels > LLVORBIS_CLIP_MAX_CHANNELS )
{
abort_decode = true;
- LL_WARNS() << "Bad channel count: " << vi->channels << LL_ENDL;
+ LL_WARNS("AudioEngine") << "Bad channel count: " << vi->channels << LL_ENDL;
}
}
else // !vi
{
abort_decode = true;
- LL_WARNS() << "No default bitstream found" << LL_ENDL;
+ LL_WARNS("AudioEngine") << "No default bitstream found" << LL_ENDL;
}
//
// This magic value is equivalent to 150MiB of data.
@@ -252,25 +253,25 @@ BOOL LLVorbisDecodeState::initDecode()
(size_t)sample_count <= 0)
{
abort_decode = true;
- LL_WARNS() << "Illegal sample count: " << sample_count << LL_ENDL;
+ LL_WARNS("AudioEngine") << "Illegal sample count: " << sample_count << LL_ENDL;
}
if( size_guess > LLVORBIS_CLIP_REJECT_SIZE ||
size_guess < 0)
{
abort_decode = true;
- LL_WARNS() << "Illegal sample size: " << size_guess << LL_ENDL;
+ LL_WARNS("AudioEngine") << "Illegal sample size: " << size_guess << LL_ENDL;
}
//
}
//
if( abort_decode )
{
- LL_WARNS() << "Canceling initDecode. Bad asset: " << mUUID << LL_ENDL;
+ LL_WARNS("AudioEngine") << "Canceling initDecode. Bad asset: " << mUUID << LL_ENDL;
vorbis_comment* comment = ov_comment(&mVF,-1);
if (comment && comment->vendor)
{
- LL_WARNS() << "Bad asset encoded by: " << comment->vendor << LL_ENDL;
+ LL_WARNS("AudioEngine") << "Bad asset encoded by: " << comment->vendor << LL_ENDL;
}
delete mInFilep;
mInFilep = NULL;
@@ -388,7 +389,7 @@ BOOL LLVorbisDecodeState::decodeSection()
{
if (!mInFilep)
{
- LL_WARNS() << "No VFS file to decode in vorbis!" << LL_ENDL;
+ LL_WARNS("AudioEngine") << "No VFS file to decode in vorbis!" << LL_ENDL;
return TRUE;
}
if (mDone)
@@ -413,7 +414,7 @@ BOOL LLVorbisDecodeState::decodeSection()
/* error in the stream. Not a problem, just reporting it in
case we (the app) cares. In this case, we don't. */
- LL_WARNS() << "BAD vorbis decode in decodeSection." << LL_ENDL;
+ LL_WARNS("AudioEngine") << "BAD vorbis decode in decodeSection." << LL_ENDL;
mValid = FALSE;
mDone = TRUE;
@@ -434,7 +435,7 @@ BOOL LLVorbisDecodeState::finishDecode()
{
if (!isValid())
{
- LL_WARNS() << "Bogus vorbis decode state for " << getUUID() << ", aborting!" << LL_ENDL;
+ LL_WARNS("AudioEngine") << "Bogus vorbis decode state for " << getUUID() << ", aborting!" << LL_ENDL;
return TRUE; // We've finished
}
@@ -515,7 +516,7 @@ BOOL LLVorbisDecodeState::finishDecode()
if (36 == data_length)
{
- LL_WARNS() << "BAD Vorbis decode in finishDecode!" << LL_ENDL;
+ LL_WARNS("AudioEngine") << "BAD Vorbis decode in finishDecode!" << LL_ENDL;
mValid = FALSE;
return TRUE; // we've finished
}
@@ -532,7 +533,7 @@ BOOL LLVorbisDecodeState::finishDecode()
{
if (mBytesRead == 0)
{
- LL_WARNS() << "Unable to write file in LLVorbisDecodeState::finishDecode" << LL_ENDL;
+ LL_WARNS("AudioEngine") << "Unable to write file in LLVorbisDecodeState::finishDecode" << LL_ENDL;
mValid = FALSE;
return TRUE; // we've finished
}
@@ -550,7 +551,7 @@ BOOL LLVorbisDecodeState::finishDecode()
LLVFile output(gVFS, mUUID, LLAssetType::AT_SOUND_WAV);
output.write(&mWAVBuffer[0], mWAVBuffer.size());
#endif
- //LL_INFOS() << "Finished decode for " << getUUID() << LL_ENDL;
+ LL_DEBUGS("AudioEngine") << "Finished decode for " << getUUID() << LL_ENDL;
return TRUE;
}
@@ -559,7 +560,7 @@ void LLVorbisDecodeState::flushBadFile()
{
if (mInFilep)
{
- LL_WARNS() << "Flushing bad vorbis file from VFS for " << mUUID << LL_ENDL;
+ LL_WARNS("AudioEngine") << "Flushing bad vorbis file from VFS for " << mUUID << LL_ENDL;
mInFilep->remove();
}
}
@@ -576,7 +577,7 @@ class LLAudioDecodeMgr::Impl
void processQueue(const F32 num_secs = 0.005);
protected:
- LLLinkedQueue mDecodeQueue;
+ std::deque mDecodeQueue;
LLPointer mCurrentDecodep;
};
@@ -608,12 +609,16 @@ void LLAudioDecodeMgr::Impl::processQueue(const F32 num_secs)
if (mCurrentDecodep->isDone() && !mCurrentDecodep->isValid())
{
// We had an error when decoding, abort.
- LL_WARNS() << mCurrentDecodep->getUUID() << " has invalid vorbis data, aborting decode" << LL_ENDL;
+ LL_WARNS("AudioEngine") << mCurrentDecodep->getUUID() << " has invalid vorbis data, aborting decode" << LL_ENDL;
mCurrentDecodep->flushBadFile();
- LLAudioData *adp = gAudiop->getAudioData(mCurrentDecodep->getUUID());
- if(adp)
+
+ if (gAudiop)
{
- adp->setLoadState(LLAudioData::STATE_LOAD_ERROR);
+ LLAudioData *adp = gAudiop->getAudioData(mCurrentDecodep->getUUID());
+ if(adp)
+ {
+ adp->setLoadState(LLAudioData::STATE_LOAD_ERROR);
+ }
}
mCurrentDecodep = NULL;
done = TRUE;
@@ -626,13 +631,13 @@ void LLAudioDecodeMgr::Impl::processQueue(const F32 num_secs)
}
else if (mCurrentDecodep)
{
- if (mCurrentDecodep->finishDecode())
+ if (gAudiop && mCurrentDecodep->finishDecode())
{
// We finished!
LLAudioData *adp = gAudiop->getAudioData(mCurrentDecodep->getUUID());
if (!adp)
{
- LL_WARNS() << "Missing LLAudioData for decode of " << mCurrentDecodep->getUUID() << LL_ENDL;
+ LL_WARNS("AudioEngine") << "Missing LLAudioData for decode of " << mCurrentDecodep->getUUID() << LL_ENDL;
}
else if (mCurrentDecodep->isValid() && mCurrentDecodep->isDone())
{
@@ -645,7 +650,7 @@ void LLAudioDecodeMgr::Impl::processQueue(const F32 num_secs)
else
{
adp->setLoadState(LLAudioData::STATE_LOAD_ERROR);
- LL_INFOS() << "Vorbis decode failed for " << mCurrentDecodep->getUUID() << LL_ENDL;
+ LL_INFOS("AudioEngine") << "Vorbis decode failed for " << mCurrentDecodep->getUUID() << LL_ENDL;
}
mCurrentDecodep = NULL;
}
@@ -655,7 +660,7 @@ void LLAudioDecodeMgr::Impl::processQueue(const F32 num_secs)
if (!done)
{
- if (!mDecodeQueue.getLength())
+ if (mDecodeQueue.empty())
{
// Nothing else on the queue.
done = TRUE;
@@ -663,8 +668,9 @@ void LLAudioDecodeMgr::Impl::processQueue(const F32 num_secs)
else
{
LLUUID uuid;
- mDecodeQueue.pop(uuid);
- if (gAudiop->hasDecodedFile(uuid))
+ uuid = mDecodeQueue.front();
+ mDecodeQueue.pop_front();
+ if (!gAudiop || gAudiop->hasDecodedFile(uuid))
{
// This file has already been decoded, don't decode it again.
continue;
@@ -715,11 +721,26 @@ void LLAudioDecodeMgr::processQueue(const F32 num_secs)
bool LLAudioDecodeMgr::addDecodeRequest(const LLUUID &uuid)
{
- if(!uuid.notNull())
- return false;
- else if (!gAssetStorage || !gAssetStorage->hasLocalAsset(uuid, LLAssetType::AT_SOUND))
- return false;
-
- mImpl->mDecodeQueue.push(uuid);
- return true;
+ if(uuid.isNull())
+ {
+ return true;
+ }
+
+ if (gAudiop && gAudiop->hasDecodedFile(uuid))
+ {
+ // Already have a decoded version, don't need to decode it.
+ LL_DEBUGS("AudioEngine") << "addDecodeRequest for " << uuid << " has decoded file already" << LL_ENDL;
+ return true;
+ }
+
+ if (gAssetStorage && gAssetStorage->hasLocalAsset(uuid, LLAssetType::AT_SOUND))
+ {
+ // Just put it on the decode queue.
+ LL_DEBUGS("AudioEngine") << "addDecodeRequest for " << uuid << " has local asset file already" << LL_ENDL;
+ mImpl->mDecodeQueue.push_back(uuid);
+ return true;
+ }
+
+ LL_DEBUGS("AudioEngine") << "addDecodeRequest for " << uuid << " no file available" << LL_ENDL;
+ return false;
}
diff --git a/indra/llaudio/llaudiodecodemgr.h b/indra/llaudio/llaudiodecodemgr.h
index 3ff894dba2..e2319a32fa 100644
--- a/indra/llaudio/llaudiodecodemgr.h
+++ b/indra/llaudio/llaudiodecodemgr.h
@@ -28,7 +28,6 @@
#include "stdtypes.h"
-#include "lllinkedqueue.h"
#include "lluuid.h"
#include "llassettype.h"
diff --git a/indra/llaudio/llaudioengine.cpp b/indra/llaudio/llaudioengine.cpp
index 99e151f126..61aa25be1e 100644
--- a/indra/llaudio/llaudioengine.cpp
+++ b/indra/llaudio/llaudioengine.cpp
@@ -1046,8 +1046,12 @@ void LLAudioEngine::cleanupAudioSource(LLAudioSource *asp)
LL_WARNS("AudioEngine") << "Cleaning up unknown audio source!" << LL_ENDL;
return;
}
- delete asp;
- mAllSources.erase(iter);
+ else
+ {
+ LL_DEBUGS("AudioEngine") << "Cleaning up audio sources for "<< asp->getID() <
-#pragma comment(lib, "delayimp.lib")
-
-bool attemptDelayLoad()
-{
- __try
- {
-#if defined(_WIN64)
- if( FAILED( __HrLoadAllImportsForDll( "fmodex64.dll" ) ) )
- return false;
-#else
- if( FAILED( __HrLoadAllImportsForDll( "fmodex.dll" ) ) )
- return false;
-#endif
- }
- __except( EXCEPTION_EXECUTE_HANDLER )
- {
- return false;
- }
- return true;
-}
-#endif
-
-static bool sVerboseDebugging = false;
-
-FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels);
-
-FMOD::ChannelGroup *LLAudioEngine_FMODEX::mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT] = {0};
-
-//This class is designed to keep track of all sound<->channel assocations.
-//Used to verify validity of sound and channel pointers, as well as catch cases were sounds
-//are released with active channels still attached.
-class CFMODSoundChecks
-{
- typedef std::map > active_sounds_t;
- typedef std::set dead_sounds_t;
- typedef std::map active_channels_t;
- typedef std::map dead_channels_t;
-
- active_sounds_t mActiveSounds;
- dead_sounds_t mDeadSounds;
- active_channels_t mActiveChannels;
- dead_channels_t mDeadChannels;
-public:
- enum STATUS
- {
- ACTIVE,
- DEAD,
- UNKNOWN
- };
- STATUS getPtrStatus(LLAudioChannel* channel)
- {
- if(!channel)
- return UNKNOWN;
- return getPtrStatus(dynamic_cast(channel)->mChannelp);
- }
- STATUS getPtrStatus(LLAudioBuffer* sound)
- {
- if(!sound)
- return UNKNOWN;
- return getPtrStatus(dynamic_cast(sound)->mSoundp);
- }
- STATUS getPtrStatus(FMOD::Channel* channel)
- {
- if(!channel)
- return UNKNOWN;
- else if(mActiveChannels.find(channel) != mActiveChannels.end())
- return ACTIVE;
- else if(mDeadChannels.find(channel) != mDeadChannels.end())
- return DEAD;
- return UNKNOWN;
- }
- STATUS getPtrStatus(FMOD::Sound* sound)
- {
- if(!sound)
- return UNKNOWN;
- if(mActiveSounds.find(sound) != mActiveSounds.end())
- return ACTIVE;
- else if(mDeadSounds.find(sound) != mDeadSounds.end())
- return DEAD;
- return UNKNOWN;
- }
- void addNewSound(FMOD::Sound* sound)
- {
- assertActiveState(sound,true,false);
-
- mDeadSounds.erase(sound);
- mActiveSounds.insert(std::make_pair(sound,std::set()));
- }
- void removeSound(FMOD::Sound* sound)
- {
- assertActiveState(sound,true);
-
- active_sounds_t::const_iterator it = mActiveSounds.find(sound);
- llassert(it != mActiveSounds.end());
- if(it != mActiveSounds.end())
- {
- if(!it->second.empty())
- {
- LL_WARNS("AudioImpl") << "Removing sound " << sound << " with attached channels: \n";
- for(std::set::iterator it2 = it->second.begin(); it2 != it->second.end();++it2)
- {
- switch(getPtrStatus(*it2))
- {
- case ACTIVE:
- LL_CONT << " Channel " << *it2 << " ACTIVE\n";
- break;
- case DEAD:
- LL_CONT << " Channel " << *it2 << " DEAD\n";
- break;
- default:
- LL_CONT << " Channel " << *it2 << " UNKNOWN\n";
- }
- }
- LL_CONT << LL_ENDL;
- }
- llassert(it->second.empty());
- mDeadSounds.insert(sound);
- mActiveSounds.erase(sound);
- }
- }
- void addNewChannelToSound(FMOD::Sound* sound,FMOD::Channel* channel)
- {
- assertActiveState(sound,true);
- assertActiveState(channel,true,false);
-
- mActiveSounds[sound].insert(channel);
- mActiveChannels.insert(std::make_pair(channel,sound));
- }
- void removeChannel(FMOD::Channel* channel)
- {
- assertActiveState(channel,true);
-
- active_channels_t::const_iterator it = mActiveChannels.find(channel);
- llassert(it != mActiveChannels.end());
- if(it != mActiveChannels.end())
- {
-#ifdef SHOW_ASSERT
- STATUS status = getPtrStatus(it->second);
- llassert(status != DEAD);
- llassert(status != UNKNOWN);
-#endif
-
- active_sounds_t::iterator it2 = mActiveSounds.find(it->second);
- llassert(it2 != mActiveSounds.end());
- if(it2 != mActiveSounds.end())
- {
- it2->second.erase(channel);
- }
- mDeadChannels.insert(*it);
- mActiveChannels.erase(channel);
- }
- }
-
- template
- void assertActiveState(T ptr, bool try_log=false, bool active=true)
- {
-#ifndef SHOW_ASSERT
- if(try_log && sVerboseDebugging)
-#endif
- {
- CFMODSoundChecks::STATUS chan = getPtrStatus(ptr);
- if(try_log && sVerboseDebugging)
- {
- if(active)
- {
- if(chan == CFMODSoundChecks::DEAD)
- LL_WARNS("AudioImpl") << __FUNCTION__ << ": Using unexpectedly dead " << typeid(T*).name() << " " << ptr << LL_ENDL;
- else if(chan == CFMODSoundChecks::UNKNOWN)
- LL_WARNS("AudioImpl") << __FUNCTION__ << ": Using unexpectedly unknown " << typeid(T*).name() << " " << ptr << LL_ENDL;
- }
- else if(chan == CFMODSoundChecks::ACTIVE)
- LL_WARNS("AudioImpl") << __FUNCTION__ << ": Using unexpectedly active " << typeid(T*).name() << " " << ptr << LL_ENDL;
- }
- llassert( active == (chan == CFMODSoundChecks::ACTIVE) );
- }
- }
-} gSoundCheck;
-
-LLAudioEngine_FMODEX::LLAudioEngine_FMODEX(bool enable_profiler, bool verbose_debugging)
-{
- sVerboseDebugging = verbose_debugging;
- mInited = false;
- mWindGen = NULL;
- mWindDSP = NULL;
- mSystem = NULL;
- mEnableProfiler = enable_profiler;
-}
-
-
-LLAudioEngine_FMODEX::~LLAudioEngine_FMODEX()
-{
-}
-
-
-inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string)
-{
- if(result == FMOD_OK)
- return false;
- LL_WARNS("AudioImpl") << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL;
- return true;
-}
-
-void* F_STDCALL decode_alloc(unsigned int size, FMOD_MEMORY_TYPE type, const char *sourcestr)
-{
- if(type & FMOD_MEMORY_STREAM_DECODE)
- {
- LL_INFOS("AudioImpl") << "Decode buffer size: " << size << LL_ENDL;
- }
- else if(type & FMOD_MEMORY_STREAM_FILE)
- {
- LL_INFOS("AudioImpl") << "Stream buffer size: " << size << LL_ENDL;
- }
- return new char[size];
-}
-void* F_STDCALL decode_realloc(void *ptr, unsigned int size, FMOD_MEMORY_TYPE type, const char *sourcestr)
-{
- memset(ptr,0,size);
- return ptr;
-}
-void F_STDCALL decode_dealloc(void *ptr, FMOD_MEMORY_TYPE type, const char *sourcestr)
-{
- delete[] (char*)ptr;
-}
-
-bool LLAudioEngine_FMODEX::init(const S32 num_channels, void* userdata)
-{
-
-#if LL_WINDOWS
- if(!attemptDelayLoad())
- return false;
-#endif
-
- U32 version = 0;
- FMOD_RESULT result;
-
- LL_DEBUGS("AppInit") << "LLAudioEngine_FMODEX::init() initializing FMOD" << LL_ENDL;
-
- //result = FMOD::Memory_Initialize(NULL, 0, &decode_alloc, &decode_realloc, &decode_dealloc, FMOD_MEMORY_STREAM_DECODE | FMOD_MEMORY_STREAM_FILE);
- //if(Check_FMOD_Error(result, "FMOD::Memory_Initialize"))
- // return false;
-
- result = FMOD::System_Create(&mSystem);
- if(Check_FMOD_Error(result, "FMOD::System_Create"))
- return false;
-
- //will call LLAudioEngine_FMODEX::allocateListener, which needs a valid mSystem pointer.
- LLAudioEngine::init(num_channels, userdata);
-
- result = mSystem->getVersion(&version);
- Check_FMOD_Error(result, "FMOD::System::getVersion");
-
- if (version < FMOD_VERSION)
- {
- LL_WARNS("AppInit") << "Error : You are using the wrong FMOD Ex version (" << version
- << ")! You should be using FMOD Ex" << FMOD_VERSION << LL_ENDL;
- }
-
-// result = mSystem->setSoftwareFormat(44100, FMOD_SOUND_FORMAT_PCM16, 0, 0, FMOD_DSP_RESAMPLER_LINEAR);
-// Check_FMOD_Error(result,"FMOD::System::setSoftwareFormat");
-
- // In this case, all sounds, PLUS wind and stream will be software.
- result = mSystem->setSoftwareChannels(num_channels + 2);
- Check_FMOD_Error(result,"FMOD::System::setSoftwareChannels");
-
- U32 fmod_flags = FMOD_INIT_NORMAL;
- if(mEnableProfiler)
- {
- fmod_flags |= FMOD_INIT_ENABLE_PROFILE;
- }
-
-#if LL_LINUX
- bool audio_ok = false;
-
- if (!audio_ok)
- {
- if (NULL == getenv("LL_BAD_FMOD_PULSEAUDIO")) /*Flawfinder: ignore*/
- {
- LL_DEBUGS("AppInit") << "Trying PulseAudio audio output..." << LL_ENDL;
- if((result = mSystem->setOutput(FMOD_OUTPUTTYPE_PULSEAUDIO)) == FMOD_OK &&
- (result = mSystem->init(num_channels + 2, fmod_flags, 0)) == FMOD_OK)
- {
- LL_DEBUGS("AppInit") << "PulseAudio output initialized OKAY" << LL_ENDL;
- audio_ok = true;
- }
- else
- {
- Check_FMOD_Error(result, "PulseAudio audio output FAILED to initialize");
- }
- }
- else
- {
- LL_DEBUGS("AppInit") << "PulseAudio audio output SKIPPED" << LL_ENDL;
- }
- }
- if (!audio_ok)
- {
- if (NULL == getenv("LL_BAD_FMOD_ALSA")) /*Flawfinder: ignore*/
- {
- LL_DEBUGS("AppInit") << "Trying ALSA audio output..." << LL_ENDL;
- if((result = mSystem->setOutput(FMOD_OUTPUTTYPE_ALSA)) == FMOD_OK &&
- (result = mSystem->init(num_channels + 2, fmod_flags, 0)) == FMOD_OK)
- {
- LL_DEBUGS("AppInit") << "ALSA audio output initialized OKAY" << LL_ENDL;
- audio_ok = true;
- }
- else
- {
- Check_FMOD_Error(result, "ALSA audio output FAILED to initialize");
- }
- }
- else
- {
- LL_DEBUGS("AppInit") << "ALSA audio output SKIPPED" << LL_ENDL;
- }
- }
- if (!audio_ok)
- {
- if (NULL == getenv("LL_BAD_FMOD_OSS")) /*Flawfinder: ignore*/
- {
- LL_DEBUGS("AppInit") << "Trying OSS audio output..." << LL_ENDL;
- if((result = mSystem->setOutput(FMOD_OUTPUTTYPE_OSS)) == FMOD_OK &&
- (result = mSystem->init(num_channels + 2, fmod_flags, 0)) == FMOD_OK)
- {
- LL_DEBUGS("AppInit") << "OSS audio output initialized OKAY" << LL_ENDL;
- audio_ok = true;
- }
- else
- {
- Check_FMOD_Error(result, "OSS audio output FAILED to initialize");
- }
- }
- else
- {
- LL_DEBUGS("AppInit") << "OSS audio output SKIPPED" << LL_ENDL;
- }
- }
- if (!audio_ok)
- {
- LL_WARNS("AppInit") << "Overall audio init failure." << LL_ENDL;
- return false;
- }
-
- // We're interested in logging which output method we
- // ended up with, for QA purposes.
- FMOD_OUTPUTTYPE output_type;
- if(!Check_FMOD_Error(mSystem->getOutput(&output_type), "FMOD::System::getOutput"))
- {
- switch (output_type)
- {
- case FMOD_OUTPUTTYPE_NOSOUND:
- LL_INFOS("AppInit") << "Audio output: NoSound" << LL_ENDL; break;
- case FMOD_OUTPUTTYPE_PULSEAUDIO:
- LL_INFOS("AppInit") << "Audio output: PulseAudio" << LL_ENDL; break;
- case FMOD_OUTPUTTYPE_ALSA:
- LL_INFOS("AppInit") << "Audio output: ALSA" << LL_ENDL; break;
- case FMOD_OUTPUTTYPE_OSS:
- LL_INFOS("AppInit") << "Audio output: OSS" << LL_ENDL; break;
- default:
- LL_INFOS("AppInit") << "Audio output: Unknown!" << LL_ENDL; break;
- };
- }
-#else // LL_LINUX
-
- // initialize the FMOD engine
- result = mSystem->init( num_channels + 2, fmod_flags, 0);
- if (result == FMOD_ERR_OUTPUT_CREATEBUFFER)
- {
- /*
- Ok, the speaker mode selected isn't supported by this soundcard. Switch it
- back to stereo...
- */
- result = mSystem->setSpeakerMode(FMOD_SPEAKERMODE_STEREO);
- Check_FMOD_Error(result,"Error falling back to stereo mode");
- /*
- ... and re-init.
- */
- result = mSystem->init( num_channels + 2, fmod_flags, 0);
- }
- if(Check_FMOD_Error(result, "Error initializing FMOD Ex"))
- return false;
-#endif
-
- if (mEnableProfiler)
- {
- Check_FMOD_Error(mSystem->createChannelGroup("None", &mChannelGroups[AUDIO_TYPE_NONE]), "FMOD::System::createChannelGroup");
- Check_FMOD_Error(mSystem->createChannelGroup("SFX", &mChannelGroups[AUDIO_TYPE_SFX]), "FMOD::System::createChannelGroup");
- Check_FMOD_Error(mSystem->createChannelGroup("UI", &mChannelGroups[AUDIO_TYPE_UI]), "FMOD::System::createChannelGroup");
- Check_FMOD_Error(mSystem->createChannelGroup("Ambient", &mChannelGroups[AUDIO_TYPE_AMBIENT]), "FMOD::System::createChannelGroup");
- }
-
- // set up our favourite FMOD-native streaming audio implementation if none has already been added
- if (!getStreamingAudioImpl()) // no existing implementation added
- setStreamingAudioImpl(new LLStreamingAudio_FMODEX(mSystem));
-
- LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init() FMOD Ex initialized correctly" << LL_ENDL;
-
- int r_numbuffers, r_samplerate, r_channels, r_bits;
- unsigned int r_bufferlength;
- char r_name[256];
- FMOD_SPEAKERMODE speaker_mode;
- if (!Check_FMOD_Error(mSystem->getDSPBufferSize(&r_bufferlength, &r_numbuffers), "FMOD::System::getDSPBufferSize") &&
- !Check_FMOD_Error(mSystem->getSoftwareFormat(&r_samplerate, NULL, &r_channels, NULL, NULL, &r_bits), "FMOD::System::getSoftwareFormat") &&
- !Check_FMOD_Error(mSystem->getDriverInfo(0, r_name, 255, 0), "FMOD::System::getDriverInfo") &&
- !Check_FMOD_Error(mSystem->getSpeakerMode(&speaker_mode), "FMOD::System::getSpeakerMode"))
- {
- std::string speaker_mode_str = "unknown";
- switch(speaker_mode)
- {
- #define SPEAKER_MODE_CASE(MODE) case MODE: speaker_mode_str = #MODE; break;
- SPEAKER_MODE_CASE(FMOD_SPEAKERMODE_RAW)
- SPEAKER_MODE_CASE(FMOD_SPEAKERMODE_MONO)
- SPEAKER_MODE_CASE(FMOD_SPEAKERMODE_STEREO)
- SPEAKER_MODE_CASE(FMOD_SPEAKERMODE_QUAD)
- SPEAKER_MODE_CASE(FMOD_SPEAKERMODE_SURROUND)
- SPEAKER_MODE_CASE(FMOD_SPEAKERMODE_5POINT1)
- SPEAKER_MODE_CASE(FMOD_SPEAKERMODE_7POINT1)
- SPEAKER_MODE_CASE(FMOD_SPEAKERMODE_SRS5_1_MATRIX)
- SPEAKER_MODE_CASE(FMOD_SPEAKERMODE_MYEARS)
- default:;
- #undef SPEAKER_MODE_CASE
- }
-
- r_name[255] = '\0';
- int latency = 1000.0 * r_bufferlength * r_numbuffers /r_samplerate;
-
- LL_INFOS("AppInit") << "FMOD device: "<< r_name << "\n"
- << "Output mode: "<< speaker_mode_str << "\n"
- << "FMOD Ex parameters: " << r_samplerate << " Hz * " << r_channels << " * " <getVersion(&version), "FMOD::System::getVersion"))
- {
- return llformat("FMOD Ex %1x.%02x.%02x", version >> 16, version >> 8 & 0x000000FF, version & 0x000000FF);
- }
- }
- return "FMODEx";
-}
-
-
-void LLAudioEngine_FMODEX::allocateListener(void)
-{
- mListenerp = (LLListener *) new LLListener_FMODEX(mSystem);
- if (!mListenerp)
- {
- LL_WARNS("AudioImpl") << "Listener creation failed" << LL_ENDL;
- }
-}
-
-
-void LLAudioEngine_FMODEX::shutdown()
-{
- LL_INFOS("AudioImpl") << "About to LLAudioEngine::shutdown()" << LL_ENDL;
- LLAudioEngine::shutdown();
-
- LL_INFOS("AudioImpl") << "LLAudioEngine_FMODEX::shutdown() closing FMOD Ex" << LL_ENDL;
- if ( mSystem ) // speculative fix for MAINT-2657
- {
- LL_INFOS("AudioImpl") << "LLAudioEngine_FMODEX::shutdown() Requesting FMOD Ex system closure" << LL_ENDL;
- Check_FMOD_Error(mSystem->close(), "FMOD::System::close");
- LL_INFOS("AudioImpl") << "LLAudioEngine_FMODEX::shutdown() Requesting FMOD Ex system release" << LL_ENDL;
- Check_FMOD_Error(mSystem->release(), "FMOD::System::release");
- }
- LL_INFOS("AudioImpl") << "LLAudioEngine_FMODEX::shutdown() done closing FMOD Ex" << LL_ENDL;
-
- delete mListenerp;
- mListenerp = NULL;
-}
-
-
-LLAudioBuffer * LLAudioEngine_FMODEX::createBuffer()
-{
- return new LLAudioBufferFMODEX(mSystem);
-}
-
-
-LLAudioChannel * LLAudioEngine_FMODEX::createChannel()
-{
- return new LLAudioChannelFMODEX(mSystem);
-}
-
-bool LLAudioEngine_FMODEX::initWind()
-{
- mNextWindUpdate = 0.0;
-
- cleanupWind();
-
-
- FMOD_DSP_DESCRIPTION dspdesc;
- memset(&dspdesc, 0, sizeof(FMOD_DSP_DESCRIPTION)); //Set everything to zero
- strncpy(dspdesc.name,"Wind Unit", sizeof(dspdesc.name)); //Set name to "Wind Unit"
- dspdesc.channels=2;
- dspdesc.read = &windCallback; //Assign callback.
- if(Check_FMOD_Error(mSystem->createDSP(&dspdesc, &mWindDSP), "FMOD::createDSP") || !mWindDSP)
- return false;
-
- float frequency = 44100;
- if (!Check_FMOD_Error(mWindDSP->getDefaults(&frequency,0,0,0), "FMOD::DSP::getDefaults"))
- {
- mWindGen = new LLWindGen((U32)frequency);
- if (!Check_FMOD_Error(mWindDSP->setUserData((void*)mWindGen), "FMOD::DSP::setUserData") &&
- !Check_FMOD_Error(mSystem->playDSP(FMOD_CHANNEL_FREE, mWindDSP, false, 0), "FMOD::System::playDSP"))
- return true; //Success
- }
-
- cleanupWind();
- return false;
-}
-
-
-void LLAudioEngine_FMODEX::cleanupWind()
-{
- if (mWindDSP)
- {
- Check_FMOD_Error(mWindDSP->remove(), "FMOD::DSP::remove");
- Check_FMOD_Error(mWindDSP->release(), "FMOD::DSP::release");
- mWindDSP = NULL;
- }
-
- delete mWindGen;
- mWindGen = NULL;
-}
-
-
-//-----------------------------------------------------------------------
-void LLAudioEngine_FMODEX::updateWind(LLVector3 wind_vec, F32 camera_height_above_water)
-{
- LLVector3 wind_pos;
- F64 pitch;
- F64 center_freq;
-
- if (!mEnableWind)
- {
- return;
- }
-
- if (mWindUpdateTimer.checkExpirationAndReset(LL_WIND_UPDATE_INTERVAL))
- {
-
- // wind comes in as Linden coordinate (+X = forward, +Y = left, +Z = up)
- // need to convert this to the conventional orientation DS3D and OpenAL use
- // where +X = right, +Y = up, +Z = backwards
-
- wind_vec.setVec(-wind_vec.mV[1], wind_vec.mV[2], -wind_vec.mV[0]);
-
- // cerr << "Wind update" << endl;
-
- pitch = 1.0 + mapWindVecToPitch(wind_vec);
- center_freq = 80.0 * pow(pitch,2.5*(mapWindVecToGain(wind_vec)+1.0));
-
- mWindGen->mTargetFreq = (F32)center_freq;
- mWindGen->mTargetGain = (F32)mapWindVecToGain(wind_vec) * mMaxWindGain;
- mWindGen->mTargetPanGainR = (F32)mapWindVecToPan(wind_vec);
- }
-}
-
-//-----------------------------------------------------------------------
-void LLAudioEngine_FMODEX::setInternalGain(F32 gain)
-{
- if (!mInited)
- {
- return;
- }
-
- gain = llclamp( gain, 0.0f, 1.0f );
-
- FMOD::ChannelGroup *master_group;
- if(Check_FMOD_Error(mSystem->getMasterChannelGroup(&master_group), "FMOD::System::getMasterChannelGroup"))
- return;
- master_group->setVolume(gain);
-
- LLStreamingAudioInterface *saimpl = getStreamingAudioImpl();
- if ( saimpl )
- {
- // fmod likes its streaming audio channel gain re-asserted after
- // master volume change.
- saimpl->setGain(saimpl->getGain());
- }
-}
-
-//
-// LLAudioChannelFMODEX implementation
-//
-
-LLAudioChannelFMODEX::LLAudioChannelFMODEX(FMOD::System *system) : LLAudioChannel(), mSystemp(system), mChannelp(NULL), mLastSamplePos(0)
-{
-}
-
-
-LLAudioChannelFMODEX::~LLAudioChannelFMODEX()
-{
- if(sVerboseDebugging)
- LL_DEBUGS("AudioImpl") << "Destructing Audio Channel. mChannelp = " << mChannelp << LL_ENDL;
-
- cleanup();
-}
-
-static FMOD_RESULT F_CALLBACK channel_callback(FMOD_CHANNEL *channel, FMOD_CHANNEL_CALLBACKTYPE type, void *commanddata1, void *commanddata2)
-{
- if(type == FMOD_CHANNEL_CALLBACKTYPE_END)
- {
- FMOD::Channel* chan = reinterpret_cast(channel);
- LLAudioChannelFMODEX* audio_channel = NULL;
- chan->getUserData((void**)&audio_channel);
- if(audio_channel)
- {
- audio_channel->onRelease();
- }
- }
- return FMOD_OK;
-}
-
-void LLAudioChannelFMODEX::onRelease()
-{
- llassert(mChannelp);
- if(sVerboseDebugging)
- LL_DEBUGS("AudioImpl") << "Fmod signaled channel release for channel " << mChannelp << LL_ENDL;
- gSoundCheck.removeChannel(mChannelp);
- mChannelp = NULL; //Null out channel here so cleanup doesn't try to redundantly stop it.
- cleanup();
-}
-
-bool LLAudioChannelFMODEX::updateBuffer()
-{
- if (LLAudioChannel::updateBuffer())
- {
- // Base class update returned true, which means the channel buffer was changed, and not is null.
-
- // Grab the FMOD sample associated with the buffer
- FMOD::Sound *soundp = ((LLAudioBufferFMODEX*)mCurrentBufferp)->getSound();
- if (!soundp)
- {
- // This is bad, there should ALWAYS be a sound associated with a legit
- // buffer.
- LL_ERRS("AudioImpl") << "No FMOD sound!" << LL_ENDL;
- return false;
- }
-
- // Actually play the sound. Start it off paused so we can do all the necessary
- // setup.
- if(!mChannelp)
- {
- FMOD_RESULT result = getSystem()->playSound(FMOD_CHANNEL_FREE, soundp, true, &mChannelp);
- Check_FMOD_Error(result, "FMOD::System::playSound");
- if(result == FMOD_OK)
- {
- if(sVerboseDebugging)
- LL_DEBUGS("AudioImpl") << "Created channel " << mChannelp << " for sound " << soundp << LL_ENDL;
-
- gSoundCheck.addNewChannelToSound(soundp,mChannelp);
- mChannelp->setCallback(&channel_callback);
- mChannelp->setUserData(this);
- }
- }
- }
-
- // If we have a source for the channel, we need to update its gain.
- if (mCurrentSourcep && mChannelp)
- {
- FMOD_RESULT result;
-
- gSoundCheck.assertActiveState(this);
- result = mChannelp->setVolume(getSecondaryGain() * mCurrentSourcep->getGain());
- Check_FMOD_Error(result, "FMOD::Channel::setVolume");
- result = mChannelp->setMode(mCurrentSourcep->isLoop() ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF);
- Check_FMOD_Error(result, "FMOD::Channel::setMode");
- }
-
- return true;
-}
-
-
-void LLAudioChannelFMODEX::update3DPosition()
-{
- if (!mChannelp)
- {
- // We're not actually a live channel (i.e., we're not playing back anything)
- return;
- }
-
- LLAudioBufferFMODEX *bufferp = (LLAudioBufferFMODEX *)mCurrentBufferp;
- if (!bufferp)
- {
- // We don't have a buffer associated with us (should really have been picked up
- // by the above if.
- return;
- }
-
- gSoundCheck.assertActiveState(this);
-
- if (mCurrentSourcep->isAmbient())
- {
- // Ambient sound, don't need to do any positional updates.
- set3DMode(false);
- }
- else
- {
- // Localized sound. Update the position and velocity of the sound.
- set3DMode(true);
-
- LLVector3 float_pos;
- float_pos.setVec(mCurrentSourcep->getPositionGlobal());
- FMOD_RESULT result = mChannelp->set3DAttributes((FMOD_VECTOR*)float_pos.mV, (FMOD_VECTOR*)mCurrentSourcep->getVelocity().mV);
- Check_FMOD_Error(result, "FMOD::Channel::set3DAttributes");
- }
-}
-
-
-void LLAudioChannelFMODEX::updateLoop()
-{
- if (!mChannelp)
- {
- // May want to clear up the loop/sample counters.
- return;
- }
-
- gSoundCheck.assertActiveState(this);
-
- //
- // Hack: We keep track of whether we looped or not by seeing when the
- // sample position looks like it's going backwards. Not reliable; may
- // yield false negatives.
- //
- U32 cur_pos;
- Check_FMOD_Error(mChannelp->getPosition(&cur_pos,FMOD_TIMEUNIT_PCMBYTES),"FMOD::Channel::getPosition");
-
- if (cur_pos < (U32)mLastSamplePos)
- {
- mLoopedThisFrame = true;
- }
- mLastSamplePos = cur_pos;
-}
-
-
-void LLAudioChannelFMODEX::cleanup()
-{
- LLAudioChannel::cleanup();
-
- if (!mChannelp)
- {
- llassert(mCurrentBufferp == NULL);
- //LL_INFOS("AudioImpl") << "Aborting cleanup with no channel handle." << LL_ENDL;
- return;
- }
-
- if(sVerboseDebugging)
- LL_DEBUGS("AudioImpl") << "Stopping channel " << mChannelp << LL_ENDL;
-
- gSoundCheck.removeChannel(mChannelp);
- mChannelp->setCallback(NULL);
- Check_FMOD_Error(mChannelp->stop(),"FMOD::Channel::stop");
-
- mChannelp = NULL;
- mLastSamplePos = 0;
-}
-
-
-void LLAudioChannelFMODEX::play()
-{
- if (!mChannelp)
- {
- LL_WARNS("AudioImpl") << "Playing without a channel handle, aborting" << LL_ENDL;
- return;
- }
-
- gSoundCheck.assertActiveState(this,true);
-
- bool paused=true;
- Check_FMOD_Error(mChannelp->getPaused(&paused), "FMOD::Channel::getPaused");
- if(!paused)
- {
- Check_FMOD_Error(mChannelp->setPaused(true), "FMOD::Channel::setPaused");
- Check_FMOD_Error(mChannelp->setPosition(0,FMOD_TIMEUNIT_PCMBYTES), "FMOD::Channel::setPosition");
- }
- Check_FMOD_Error(mChannelp->setPaused(false), "FMOD::Channel::setPaused");
-
- if(sVerboseDebugging)
- LL_DEBUGS("AudioImpl") << "Playing channel " << mChannelp << LL_ENDL;
-
- getSource()->setPlayedOnce(true);
-
- if(LLAudioEngine_FMODEX::mChannelGroups[getSource()->getType()])
- Check_FMOD_Error(mChannelp->setChannelGroup(LLAudioEngine_FMODEX::mChannelGroups[getSource()->getType()]),"FMOD::Channel::setChannelGroup");
-}
-
-
-void LLAudioChannelFMODEX::playSynced(LLAudioChannel *channelp)
-{
- LLAudioChannelFMODEX *fmod_channelp = (LLAudioChannelFMODEX*)channelp;
- if (!(fmod_channelp->mChannelp && mChannelp))
- {
- // Don't have channels allocated to both the master and the slave
- return;
- }
-
- gSoundCheck.assertActiveState(this,true);
-
- U32 cur_pos;
- if(Check_FMOD_Error(fmod_channelp->mChannelp->getPosition(&cur_pos,FMOD_TIMEUNIT_PCMBYTES), "Unable to retrieve current position"))
- return;
-
- cur_pos %= mCurrentBufferp->getLength();
-
- // Try to match the position of our sync master
- Check_FMOD_Error(mChannelp->setPosition(cur_pos,FMOD_TIMEUNIT_PCMBYTES),"Unable to set current position");
-
- // Start us playing
- play();
-}
-
-
-bool LLAudioChannelFMODEX::isPlaying()
-{
- if (!mChannelp)
- {
- return false;
- }
-
- gSoundCheck.assertActiveState(this);
-
- bool paused, playing;
- Check_FMOD_Error(mChannelp->getPaused(&paused),"FMOD::Channel::getPaused");
- Check_FMOD_Error(mChannelp->isPlaying(&playing),"FMOD::Channel::isPlaying");
- return !paused && playing;
-}
-
-
-//
-// LLAudioChannelFMODEX implementation
-//
-
-
-LLAudioBufferFMODEX::LLAudioBufferFMODEX(FMOD::System *system) : LLAudioBuffer(), mSystemp(system), mSoundp(NULL)
-{
-}
-
-
-LLAudioBufferFMODEX::~LLAudioBufferFMODEX()
-{
- if(mSoundp)
- {
- if(sVerboseDebugging)
- LL_DEBUGS("AudioImpl") << "Release sound " << mSoundp << LL_ENDL;
-
- gSoundCheck.removeSound(mSoundp);
- Check_FMOD_Error(mSoundp->release(),"FMOD::Sound::Release");
- mSoundp = NULL;
- }
-}
-
-
-bool LLAudioBufferFMODEX::loadWAV(const std::string& filename)
-{
- // Try to open a wav file from disk. This will eventually go away, as we don't
- // really want to block doing this.
- if (filename.empty())
- {
- // invalid filename, abort.
- return false;
- }
-
- if (!LLAPRFile::isExist(filename, LL_APR_RPB))
- {
- // File not found, abort.
- return false;
- }
-
- if (mSoundp)
- {
- gSoundCheck.removeSound(mSoundp);
- // If there's already something loaded in this buffer, clean it up.
- Check_FMOD_Error(mSoundp->release(),"FMOD::Sound::release");
- mSoundp = NULL;
- }
-
- FMOD_MODE base_mode = FMOD_LOOP_NORMAL | FMOD_SOFTWARE;
- FMOD_CREATESOUNDEXINFO exinfo;
- memset(&exinfo,0,sizeof(exinfo));
- exinfo.cbsize = sizeof(exinfo);
- exinfo.suggestedsoundtype = FMOD_SOUND_TYPE_WAV; //Hint to speed up loading.
- // Load up the wav file into an fmod sample
-#if LL_WINDOWS
- FMOD_RESULT result = getSystem()->createSound((const char*)utf8str_to_utf16str(filename).c_str(), base_mode | FMOD_UNICODE, &exinfo, &mSoundp);
-#else
- FMOD_RESULT result = getSystem()->createSound(filename.c_str(), base_mode, &exinfo, &mSoundp);
-#endif
-
- if (result != FMOD_OK)
- {
- // We failed to load the file for some reason.
- LL_WARNS("AudioImpl") << "Could not load data '" << filename << "': " << FMOD_ErrorString(result) << LL_ENDL;
-
- //
- // If we EVER want to load wav files provided by end users, we need
- // to rethink this!
- //
- // file is probably corrupt - remove it.
- LLFile::remove(filename);
- return false;
- }
-
- gSoundCheck.addNewSound(mSoundp);
-
- // Everything went well, return true
- return true;
-}
-
-
-U32 LLAudioBufferFMODEX::getLength()
-{
- if (!mSoundp)
- {
- return 0;
- }
-
- gSoundCheck.assertActiveState(this);
- U32 length;
- Check_FMOD_Error(mSoundp->getLength(&length, FMOD_TIMEUNIT_PCMBYTES),"FMOD::Sound::getLength");
- return length;
-}
-
-
-void LLAudioChannelFMODEX::set3DMode(bool use3d)
-{
- gSoundCheck.assertActiveState(this);
-
- FMOD_MODE current_mode;
- if(Check_FMOD_Error(mChannelp->getMode(¤t_mode),"FMOD::Channel::getMode"))
- return;
- FMOD_MODE new_mode = current_mode;
- new_mode &= ~(use3d ? FMOD_2D : FMOD_3D);
- new_mode |= use3d ? FMOD_3D : FMOD_2D;
-
- if(current_mode != new_mode)
- {
- Check_FMOD_Error(mChannelp->setMode(new_mode),"FMOD::Channel::setMode");
- }
-}
-
-
-FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *originalbuffer, float *newbuffer, unsigned int length, int inchannels, int outchannels)
-{
- // originalbuffer = fmod's original mixbuffer.
- // newbuffer = the buffer passed from the previous DSP unit.
- // length = length in samples at this mix time.
- // userdata = user parameter passed through in FSOUND_DSP_Create.
-
- LLWindGen *windgen;
- FMOD::DSP *thisdsp = (FMOD::DSP *)dsp_state->instance;
-
- thisdsp->getUserData((void **)&windgen);
-
- if (windgen)
- windgen->windGenerate((LLAudioEngine_FMODEX::MIXBUFFERFORMAT *)newbuffer, length);
-
- return FMOD_OK;
-}
diff --git a/indra/llaudio/llaudioengine_fmodex.h b/indra/llaudio/llaudioengine_fmodex.h
deleted file mode 100644
index fe93d8c487..0000000000
--- a/indra/llaudio/llaudioengine_fmodex.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/**
- * @file audioengine_FMODEX.h
- * @brief Definition of LLAudioEngine class abstracting the audio
- * support as a FMOD 3D implementation
- *
- * $LicenseInfo:firstyear=2002&license=viewergpl$
- *
- * Copyright (c) 2002-2009, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-#ifndef LL_AUDIOENGINE_FMODEX_H
-#define LL_AUDIOENGINE_FMODEX_H
-
-#include "llaudioengine.h"
-#include "lllistener_fmodex.h"
-#include "llwindgen.h"
-
-//Stubs
-class LLAudioStreamManagerFMODEX;
-namespace FMOD
-{
- class System;
- class Channel;
- class ChannelGroup;
- class Sound;
- class DSP;
-}
-
-//Interfaces
-class LLAudioEngine_FMODEX : public LLAudioEngine
-{
-public:
- LLAudioEngine_FMODEX(bool enable_profiler, bool verbose_debugging);
- virtual ~LLAudioEngine_FMODEX();
-
- // initialization/startup/shutdown
- virtual bool init(const S32 num_channels, void *user_data);
- virtual std::string getDriverName(bool verbose);
- virtual void allocateListener();
-
- virtual void shutdown();
-
- /*virtual*/ bool initWind();
- /*virtual*/ void cleanupWind();
-
- /*virtual*/void updateWind(LLVector3 direction, F32 camera_height_above_water);
-
- typedef F32 MIXBUFFERFORMAT;
-
- FMOD::System *getSystem() const {return mSystem;}
-protected:
- /*virtual*/ LLAudioBuffer *createBuffer(); // Get a free buffer, or flush an existing one if you have to.
- /*virtual*/ LLAudioChannel *createChannel(); // Create a new audio channel.
-
- /*virtual*/ void setInternalGain(F32 gain);
-
- bool mInited;
-
- LLWindGen *mWindGen;
-
- FMOD::DSP *mWindDSP;
- FMOD::System *mSystem;
- bool mEnableProfiler;
-
-public:
- static FMOD::ChannelGroup *mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT];
-};
-
-
-class LLAudioChannelFMODEX : public LLAudioChannel
-{
-public:
- LLAudioChannelFMODEX(FMOD::System *audioengine);
- virtual ~LLAudioChannelFMODEX();
- void onRelease();
-protected:
- /*virtual*/ void play();
- /*virtual*/ void playSynced(LLAudioChannel *channelp);
- /*virtual*/ void cleanup();
- /*virtual*/ bool isPlaying();
-
- /*virtual*/ bool updateBuffer();
- /*virtual*/ void update3DPosition();
- /*virtual*/ void updateLoop();
-
- void set3DMode(bool use3d);
-protected:
- FMOD::System *getSystem() const {return mSystemp;}
- FMOD::System *mSystemp;
- FMOD::Channel *mChannelp;
- S32 mLastSamplePos;
-
- friend class CFMODSoundChecks;
-};
-
-
-class LLAudioBufferFMODEX : public LLAudioBuffer
-{
-public:
- LLAudioBufferFMODEX(FMOD::System *audioengine);
- virtual ~LLAudioBufferFMODEX();
-
- /*virtual*/ bool loadWAV(const std::string& filename);
- /*virtual*/ U32 getLength();
- friend class LLAudioChannelFMODEX;
-protected:
- FMOD::System *getSystem() const {return mSystemp;}
- FMOD::System *mSystemp;
- FMOD::Sound *getSound() const{ return mSoundp; }
- FMOD::Sound *mSoundp;
-
- friend class CFMODSoundChecks;
-};
-
-
-#endif // LL_AUDIOENGINE_FMODEX_H
diff --git a/indra/llaudio/llaudioengine_fmodstudio.cpp b/indra/llaudio/llaudioengine_fmodstudio.cpp
index 93541d3de8..823f51cbf2 100644
--- a/indra/llaudio/llaudioengine_fmodstudio.cpp
+++ b/indra/llaudio/llaudioengine_fmodstudio.cpp
@@ -1,5 +1,5 @@
/**
- * @file audioengine_FMODSTUDIO.cpp
+ * @file audioengine_fmodstudio.cpp
* @brief Implementation of LLAudioEngine class abstracting the audio support as a FMOD 3D implementation
*
* $LicenseInfo:firstyear=2002&license=viewergpl$
@@ -45,7 +45,6 @@
#include "fmod.hpp"
#include "fmod_errors.h"
#include "lldir.h"
-#include "llapr.h"
#include "sound_ids.h"
@@ -79,7 +78,7 @@ bool attemptDelayLoad()
static bool sVerboseDebugging = false;
-FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels);
+FMOD_RESULT F_CALLBACK windDSPCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels);
FMOD::ChannelGroup *LLAudioEngine_FMODSTUDIO::mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT] = {0};
@@ -234,21 +233,20 @@ class CFMODSoundChecks
} gSoundCheck;
LLAudioEngine_FMODSTUDIO::LLAudioEngine_FMODSTUDIO(bool enable_profiler, bool verbose_debugging)
+ : mInited(false)
+ , mWindGen(NULL)
+ , mWindDSPDesc(NULL)
+ , mWindDSP(NULL)
+ , mSystem(NULL)
+ , mEnableProfiler(enable_profiler)
{
sVerboseDebugging = verbose_debugging;
- mInited = false;
- mWindGen = NULL;
- mWindDSP = NULL;
- mSystem = NULL;
- mEnableProfiler = enable_profiler;
}
-
LLAudioEngine_FMODSTUDIO::~LLAudioEngine_FMODSTUDIO()
{
}
-
inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string)
{
if(result == FMOD_OK)
@@ -257,45 +255,20 @@ inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string)
return true;
}
-void* F_STDCALL decode_alloc(unsigned int size, FMOD_MEMORY_TYPE type, const char *sourcestr)
-{
- if(type & FMOD_MEMORY_STREAM_DECODE)
- {
- LL_INFOS("AudioImpl") << "Decode buffer size: " << size << LL_ENDL;
- }
- else if(type & FMOD_MEMORY_STREAM_FILE)
- {
- LL_INFOS("AudioImpl") << "Stream buffer size: " << size << LL_ENDL;
- }
- return new char[size];
-}
-void* F_STDCALL decode_realloc(void *ptr, unsigned int size, FMOD_MEMORY_TYPE type, const char *sourcestr)
-{
- memset(ptr,0,size);
- return ptr;
-}
-void F_STDCALL decode_dealloc(void *ptr, FMOD_MEMORY_TYPE type, const char *sourcestr)
-{
- delete[] (char*)ptr;
-}
-
bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata)
{
-
-#if LL_WINDOWS
+ LL_WARNS("AudioImpl") << "BARKBARKBARK" << LL_ENDL;
+#if 0 //LL_WINDOWS
if(!attemptDelayLoad())
return false;
#endif
U32 version = 0;
+
FMOD_RESULT result;
LL_DEBUGS("AppInit") << "LLAudioEngine_FMODSTUDIO::init() initializing FMOD" << LL_ENDL;
- //result = FMOD::Memory_Initialize(NULL, 0, &decode_alloc, &decode_realloc, &decode_dealloc, FMOD_MEMORY_STREAM_DECODE | FMOD_MEMORY_STREAM_FILE);
- //if(Check_FMOD_Error(result, "FMOD::Memory_Initialize"))
- // return false;
-
result = FMOD::System_Create(&mSystem);
if(Check_FMOD_Error(result, "FMOD::System_Create"))
return false;
@@ -477,7 +450,7 @@ std::string LLAudioEngine_FMODSTUDIO::getDriverName(bool verbose)
return llformat("FMOD Studio %1x.%02x.%02x", version >> 16, version >> 8 & 0x000000FF, version & 0x000000FF);
}
}
- return "FMODEx";
+ return "FMOD Studio";
}
@@ -528,24 +501,25 @@ bool LLAudioEngine_FMODSTUDIO::initWind()
cleanupWind();
- FMOD_DSP_DESCRIPTION dspdesc;
- memset(&dspdesc, 0, sizeof(FMOD_DSP_DESCRIPTION)); //Set everything to zero
- dspdesc.pluginsdkversion = FMOD_PLUGIN_SDK_VERSION;
- strncpy(dspdesc.name,"Wind Unit", sizeof(dspdesc.name)); //Set name to "Wind Unit"
- dspdesc.numoutputbuffers = 1;
- dspdesc.read = &windCallback; //Assign callback.
- if (Check_FMOD_Error(mSystem->createDSP(&dspdesc, &mWindDSP), "FMOD::createDSP") || !mWindDSP)
+ mWindDSPDesc = new FMOD_DSP_DESCRIPTION();
+ memset(mWindDSPDesc, 0, sizeof(*mWindDSPDesc)); //Set everything to zero
+ mWindDSPDesc->pluginsdkversion = FMOD_PLUGIN_SDK_VERSION;
+ strncpy(mWindDSPDesc->name, "Wind Unit", sizeof(mWindDSPDesc->name)); //Set name to "Wind Unit"
+ mWindDSPDesc->numoutputbuffers = 1;
+ mWindDSPDesc->read = &windDSPCallback; //Assign callback.
+ if (Check_FMOD_Error(mSystem->createDSP(mWindDSPDesc, &mWindDSP), "FMOD::createDSP") || !mWindDSP)
return false;
int frequency = 44100;
- if (!Check_FMOD_Error(mSystem->getSoftwareFormat(&frequency, NULL, NULL), "FMOD::System::getSoftwareFormat"))
+ FMOD_SPEAKERMODE mode;
+ if (!Check_FMOD_Error(mSystem->getSoftwareFormat(&frequency, &mode, NULL), "FMOD::System::getSoftwareFormat"))
{
mWindGen = new LLWindGen((U32)frequency);
- FMOD_SPEAKERMODE mode;
+
if (!Check_FMOD_Error(mWindDSP->setUserData((void*)mWindGen), "FMOD::DSP::setUserData") &&
- !Check_FMOD_Error(mSystem->playDSP(mWindDSP, NULL, false, 0), "FMOD::System::playDSP") &&
!Check_FMOD_Error(mSystem->getSoftwareFormat(NULL, &mode, NULL), "FMOD::System::getSoftwareFormat") &&
- !Check_FMOD_Error(mWindDSP->setChannelFormat(FMOD_CHANNELMASK_STEREO, 2, mode), "FMOD::DSP::setChannelFormat"))
+ !Check_FMOD_Error(mWindDSP->setChannelFormat(FMOD_CHANNELMASK_STEREO, 2, mode), "FMOD::DSP::setChannelFormat") &&
+ !Check_FMOD_Error(mSystem->playDSP(mWindDSP, NULL, false, 0), "FMOD::System::playDSP"))
return true; //Success
}
@@ -565,6 +539,9 @@ void LLAudioEngine_FMODSTUDIO::cleanupWind()
mWindDSP = NULL;
}
+ delete mWindDSPDesc;
+ mWindDSPDesc = NULL;
+
delete mWindGen;
mWindGen = NULL;
}
@@ -686,6 +663,7 @@ bool LLAudioChannelFMODSTUDIO::updateBuffer()
return false;
}
+
// Actually play the sound. Start it off paused so we can do all the necessary
// setup.
if(!mChannelp)
@@ -909,7 +887,7 @@ bool LLAudioBufferFMODSTUDIO::loadWAV(const std::string& filename)
return false;
}
- if (!LLAPRFile::isExist(filename, LL_APR_RPB))
+ if (!gDirUtilp->fileExists(filename))
{
// File not found, abort.
return false;
@@ -924,8 +902,7 @@ bool LLAudioBufferFMODSTUDIO::loadWAV(const std::string& filename)
}
FMOD_MODE base_mode = FMOD_LOOP_NORMAL;
- FMOD_CREATESOUNDEXINFO exinfo;
- memset(&exinfo,0,sizeof(exinfo));
+ FMOD_CREATESOUNDEXINFO exinfo = { };
exinfo.cbsize = sizeof(exinfo);
exinfo.suggestedsoundtype = FMOD_SOUND_TYPE_WAV; //Hint to speed up loading.
// Load up the wav file into an fmod sample
@@ -983,7 +960,7 @@ void LLAudioChannelFMODSTUDIO::set3DMode(bool use3d)
}
-FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels)
+FMOD_RESULT F_CALLBACK windDSPCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels)
{
// inbuffer = incomming data.
// newbuffer = outgoing data. AKA this DSP's output.
diff --git a/indra/llaudio/llaudioengine_fmodstudio.h b/indra/llaudio/llaudioengine_fmodstudio.h
index 730a702a1a..ff45d3ecb9 100644
--- a/indra/llaudio/llaudioengine_fmodstudio.h
+++ b/indra/llaudio/llaudioengine_fmodstudio.h
@@ -48,6 +48,7 @@ namespace FMOD
class Sound;
class DSP;
}
+typedef struct FMOD_DSP_DESCRIPTION FMOD_DSP_DESCRIPTION;
//Interfaces
class LLAudioEngine_FMODSTUDIO : public LLAudioEngine
@@ -81,6 +82,7 @@ class LLAudioEngine_FMODSTUDIO : public LLAudioEngine
LLWindGen *mWindGen;
+ FMOD_DSP_DESCRIPTION *mWindDSPDesc;
FMOD::DSP *mWindDSP;
FMOD::System *mSystem;
bool mEnableProfiler;
diff --git a/indra/llaudio/lllistener.cpp b/indra/llaudio/lllistener.cpp
index df2366c8c2..0723fdbebe 100644
--- a/indra/llaudio/lllistener.cpp
+++ b/indra/llaudio/lllistener.cpp
@@ -28,15 +28,18 @@
#include "lllistener.h"
-#define DEFAULT_AT 0.0f,0.0f,-1.0f
-#define DEFAULT_UP 0.0f,1.0f,0.0f
+const LLVector3 DEFAULT_AT(0.0f, 0.0f, -1.0f);
+const LLVector3 DEFAULT_UP(0.0f, 1.0f, 0.0f);
//-----------------------------------------------------------------------
// constructor
//-----------------------------------------------------------------------
LLListener::LLListener()
+ : mPosition(LLVector3::zero),
+ mListenAt(DEFAULT_AT),
+ mListenUp(DEFAULT_UP),
+ mVelocity(LLVector3::zero)
{
- init();
}
//-----------------------------------------------------------------------
@@ -44,15 +47,6 @@ LLListener::~LLListener()
{
}
-//-----------------------------------------------------------------------
-void LLListener::init(void)
-{
- mPosition.zeroVec();
- mListenAt.setVec(DEFAULT_AT);
- mListenUp.setVec(DEFAULT_UP);
- mVelocity.zeroVec();
-}
-
//-----------------------------------------------------------------------
void LLListener::translate(LLVector3 offset)
{
@@ -99,9 +93,6 @@ void LLListener::orient(LLVector3 up, LLVector3 at)
//-----------------------------------------------------------------------
void LLListener::set(LLVector3 pos, LLVector3 vel, LLVector3 up, LLVector3 at)
{
- mPosition = pos;
- mVelocity = vel;
-
setPosition(pos);
setVelocity(vel);
orient(up,at);
diff --git a/indra/llaudio/lllistener.h b/indra/llaudio/lllistener.h
index 41836bf039..11c1ad2ae1 100644
--- a/indra/llaudio/lllistener.h
+++ b/indra/llaudio/lllistener.h
@@ -45,7 +45,6 @@ class LLListener
public:
LLListener();
virtual ~LLListener();
- virtual void init();
virtual void set(LLVector3 pos, LLVector3 vel, LLVector3 up, LLVector3 at);
diff --git a/indra/llaudio/lllistener_fmodex.cpp b/indra/llaudio/lllistener_fmodex.cpp
deleted file mode 100644
index e70dc7c60c..0000000000
--- a/indra/llaudio/lllistener_fmodex.cpp
+++ /dev/null
@@ -1,141 +0,0 @@
-/**
- * @file listener_fmod.cpp
- * @brief implementation of LISTENER class abstracting the audio
- * support as a FMOD 3D implementation (windows only)
- *
- * $LicenseInfo:firstyear=2002&license=viewergpl$
- *
- * Copyright (c) 2002-2009, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-#include "linden_common.h"
-#include "llaudioengine.h"
-#include "lllistener_fmodex.h"
-#include "fmod.hpp"
-
-//-----------------------------------------------------------------------
-// constructor
-//-----------------------------------------------------------------------
-LLListener_FMODEX::LLListener_FMODEX(FMOD::System *system)
-{
- mSystem = system;
- init();
-}
-
-//-----------------------------------------------------------------------
-LLListener_FMODEX::~LLListener_FMODEX()
-{
-}
-
-//-----------------------------------------------------------------------
-void LLListener_FMODEX::init(void)
-{
- // do inherited
- LLListener::init();
- mDopplerFactor = 1.0f;
- mRolloffFactor = 1.0f;
-}
-
-//-----------------------------------------------------------------------
-void LLListener_FMODEX::translate(LLVector3 offset)
-{
- LLListener::translate(offset);
-
- mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV);
-}
-
-//-----------------------------------------------------------------------
-void LLListener_FMODEX::setPosition(LLVector3 pos)
-{
- LLListener::setPosition(pos);
-
- mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV);
-}
-
-//-----------------------------------------------------------------------
-void LLListener_FMODEX::setVelocity(LLVector3 vel)
-{
- LLListener::setVelocity(vel);
-
- mSystem->set3DListenerAttributes(0, NULL, (FMOD_VECTOR*)mVelocity.mV, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV);
-}
-
-//-----------------------------------------------------------------------
-void LLListener_FMODEX::orient(LLVector3 up, LLVector3 at)
-{
- LLListener::orient(up, at);
-
- // Welcome to the transition between right and left
- // (coordinate systems, that is)
- // Leaving the at vector alone results in a L/R reversal
- // since DX is left-handed and we (LL, OpenGL, OpenAL) are right-handed
- at = -at;
-
- mSystem->set3DListenerAttributes(0, NULL, NULL, (FMOD_VECTOR*)at.mV, (FMOD_VECTOR*)up.mV);
-}
-
-//-----------------------------------------------------------------------
-void LLListener_FMODEX::commitDeferredChanges()
-{
- mSystem->update();
-}
-
-
-void LLListener_FMODEX::setRolloffFactor(F32 factor)
-{
- //An internal FMODEx optimization skips 3D updates if there have not been changes to the 3D sound environment.
- //Sadly, a change in rolloff is not accounted for, thus we must touch the listener properties as well.
- //In short: Changing the position ticks a dirtyflag inside fmodex, which makes it not skip 3D processing next update call.
- if(mRolloffFactor != factor)
- {
- LLVector3 pos = mVelocity - LLVector3(0.f,0.f,.1f);
- mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)pos.mV, NULL, NULL, NULL);
- mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mVelocity.mV, NULL, NULL, NULL);
- }
- mRolloffFactor = factor;
- mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor);
-}
-
-
-F32 LLListener_FMODEX::getRolloffFactor()
-{
- return mRolloffFactor;
-}
-
-
-void LLListener_FMODEX::setDopplerFactor(F32 factor)
-{
- mDopplerFactor = factor;
- mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor);
-}
-
-
-F32 LLListener_FMODEX::getDopplerFactor()
-{
- return mDopplerFactor;
-}
-
-
diff --git a/indra/llaudio/lllistener_fmodex.h b/indra/llaudio/lllistener_fmodex.h
deleted file mode 100644
index 8a91b3a2ed..0000000000
--- a/indra/llaudio/lllistener_fmodex.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/**
- * @file listener_fmod.h
- * @brief Description of LISTENER class abstracting the audio support
- * as an FMOD 3D implementation (windows and Linux)
- *
- * $LicenseInfo:firstyear=2002&license=viewergpl$
- *
- * Copyright (c) 2002-2009, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-#ifndef LL_LISTENER_FMODEX_H
-#define LL_LISTENER_FMODEX_H
-
-#include "lllistener.h"
-
-//Stubs
-namespace FMOD
-{
- class System;
-}
-
-//Interfaces
-class LLListener_FMODEX : public LLListener
-{
- public:
- LLListener_FMODEX(FMOD::System *system);
- virtual ~LLListener_FMODEX();
- virtual void init();
-
- virtual void translate(LLVector3 offset);
- virtual void setPosition(LLVector3 pos);
- virtual void setVelocity(LLVector3 vel);
- virtual void orient(LLVector3 up, LLVector3 at);
- virtual void commitDeferredChanges();
-
- virtual void setDopplerFactor(F32 factor);
- virtual F32 getDopplerFactor();
- virtual void setRolloffFactor(F32 factor);
- virtual F32 getRolloffFactor();
- protected:
- FMOD::System *mSystem;
- F32 mDopplerFactor;
- F32 mRolloffFactor;
-};
-
-#endif
-
-
diff --git a/indra/llaudio/lllistener_fmodstudio.cpp b/indra/llaudio/lllistener_fmodstudio.cpp
index e2074ce2da..42d819ef66 100644
--- a/indra/llaudio/lllistener_fmodstudio.cpp
+++ b/indra/llaudio/lllistener_fmodstudio.cpp
@@ -39,10 +39,12 @@
//-----------------------------------------------------------------------
// constructor
//-----------------------------------------------------------------------
-LLListener_FMODSTUDIO::LLListener_FMODSTUDIO(FMOD::System *system)
+LLListener_FMODSTUDIO::LLListener_FMODSTUDIO(FMOD::System *system)
+ : LLListener(),
+ mDopplerFactor(1.0f),
+ mRolloffFactor(1.0f)
{
mSystem = system;
- init();
}
//-----------------------------------------------------------------------
@@ -50,21 +52,12 @@ LLListener_FMODSTUDIO::~LLListener_FMODSTUDIO()
{
}
-//-----------------------------------------------------------------------
-void LLListener_FMODSTUDIO::init(void)
-{
- // do inherited
- LLListener::init();
- mDopplerFactor = 1.0f;
- mRolloffFactor = 1.0f;
-}
-
//-----------------------------------------------------------------------
void LLListener_FMODSTUDIO::translate(LLVector3 offset)
{
LLListener::translate(offset);
- mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV);
+ mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, NULL, NULL);
}
//-----------------------------------------------------------------------
@@ -72,7 +65,7 @@ void LLListener_FMODSTUDIO::setPosition(LLVector3 pos)
{
LLListener::setPosition(pos);
- mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV);
+ mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, NULL, NULL);
}
//-----------------------------------------------------------------------
@@ -80,7 +73,7 @@ void LLListener_FMODSTUDIO::setVelocity(LLVector3 vel)
{
LLListener::setVelocity(vel);
- mSystem->set3DListenerAttributes(0, NULL, (FMOD_VECTOR*)mVelocity.mV, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV);
+ mSystem->set3DListenerAttributes(0, NULL, (FMOD_VECTOR*)mVelocity.mV, NULL, NULL);
}
//-----------------------------------------------------------------------
@@ -94,20 +87,25 @@ void LLListener_FMODSTUDIO::orient(LLVector3 up, LLVector3 at)
//-----------------------------------------------------------------------
void LLListener_FMODSTUDIO::commitDeferredChanges()
{
+ if(!mSystem)
+ {
+ return;
+ }
+
mSystem->update();
}
void LLListener_FMODSTUDIO::setRolloffFactor(F32 factor)
{
- //An internal FMODEx optimization skips 3D updates if there have not been changes to the 3D sound environment.
+ //An internal FMOD Studio optimization skips 3D updates if there have not been changes to the 3D sound environment.
//Sadly, a change in rolloff is not accounted for, thus we must touch the listener properties as well.
- //In short: Changing the position ticks a dirtyflag inside fmodstudio, which makes it not skip 3D processing next update call.
+ //In short: Changing the position ticks a dirtyflag inside fmod studio, which makes it not skip 3D processing next update call.
if(mRolloffFactor != factor)
{
- LLVector3 pos = mVelocity - LLVector3(0.f,0.f,.1f);
- mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)pos.mV, NULL, NULL, NULL);
- mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mVelocity.mV, NULL, NULL, NULL);
+ LLVector3 tmp_pos = mPosition - LLVector3(0.f,0.f,.1f);
+ mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*) tmp_pos.mV, NULL, NULL, NULL);
+ mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*) mPosition.mV, NULL, NULL, NULL);
}
mRolloffFactor = factor;
mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor);
diff --git a/indra/llaudio/lllistener_fmodstudio.h b/indra/llaudio/lllistener_fmodstudio.h
index 516f4eae82..de9a5e9ca6 100644
--- a/indra/llaudio/lllistener_fmodstudio.h
+++ b/indra/llaudio/lllistener_fmodstudio.h
@@ -48,7 +48,6 @@ class LLListener_FMODSTUDIO : public LLListener
public:
LLListener_FMODSTUDIO(FMOD::System *system);
virtual ~LLListener_FMODSTUDIO();
- virtual void init();
virtual void translate(LLVector3 offset);
virtual void setPosition(LLVector3 pos);
diff --git a/indra/llaudio/lllistener_openal.cpp b/indra/llaudio/lllistener_openal.cpp
index 462484e33b..d1734a930d 100644
--- a/indra/llaudio/lllistener_openal.cpp
+++ b/indra/llaudio/lllistener_openal.cpp
@@ -31,21 +31,15 @@
#include "lllistener_openal.h"
LLListener_OpenAL::LLListener_OpenAL()
+ : LLListener(),
+ mRolloffFactor(1.f)
{
- init();
}
LLListener_OpenAL::~LLListener_OpenAL()
{
}
-void LLListener_OpenAL::init()
-{
- // do inherited
- LLListener::init();
- mRolloffFactor = 1.0f;
-}
-
void LLListener_OpenAL::translate(LLVector3 offset)
{
//LL_INFOS() << "LLListener_OpenAL::translate() : " << offset << LL_ENDL;
@@ -71,18 +65,20 @@ void LLListener_OpenAL::orient(LLVector3 up, LLVector3 at)
void LLListener_OpenAL::commitDeferredChanges()
{
- ALfloat orientation[6];
- orientation[0] = mListenAt.mV[0];
- orientation[1] = mListenAt.mV[1];
- orientation[2] = mListenAt.mV[2];
- orientation[3] = mListenUp.mV[0];
- orientation[4] = mListenUp.mV[1];
- orientation[5] = mListenUp.mV[2];
-
- ALfloat velocity[3];
- velocity[0] = mVelocity.mV[0];
- velocity[1] = mVelocity.mV[1];
- velocity[2] = mVelocity.mV[2];
+ ALfloat orientation[] = {
+ mListenAt.mV[0],
+ mListenAt.mV[1],
+ mListenAt.mV[2],
+ mListenUp.mV[0],
+ mListenUp.mV[1],
+ mListenUp.mV[2],
+ };
+
+ ALfloat velocity[3] = {
+ mVelocity.mV[0],
+ mVelocity.mV[1],
+ mVelocity.mV[2],
+ };
alListenerfv(AL_ORIENTATION, orientation);
alListenerfv(AL_POSITION, mPosition.mV);
diff --git a/indra/llaudio/lllistener_openal.h b/indra/llaudio/lllistener_openal.h
index 96af86d998..cb163b11a5 100644
--- a/indra/llaudio/lllistener_openal.h
+++ b/indra/llaudio/lllistener_openal.h
@@ -38,7 +38,6 @@ class LLListener_OpenAL : public LLListener
public:
LLListener_OpenAL();
virtual ~LLListener_OpenAL();
- virtual void init();
virtual void translate(LLVector3 offset);
virtual void setPosition(LLVector3 pos);
diff --git a/indra/llaudio/llstreamingaudio_fmodex.cpp b/indra/llaudio/llstreamingaudio_fmodex.cpp
deleted file mode 100644
index 39436977a8..0000000000
--- a/indra/llaudio/llstreamingaudio_fmodex.cpp
+++ /dev/null
@@ -1,596 +0,0 @@
-/**
- * @file streamingaudio_fmod.cpp
- * @brief LLStreamingAudio_FMODEX implementation
- *
- * $LicenseInfo:firstyear=2009&license=viewergpl$
- *
- * Copyright (c) 2009, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-#include "linden_common.h"
-
-#include "llmath.h"
-
-#include "fmod.hpp"
-#include "fmod_errors.h"
-
-#include "llstreamingaudio_fmodex.h"
-
-inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string)
-{
- if (result == FMOD_OK)
- return false;
- LL_WARNS("AudioImpl") << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL;
- return true;
-}
-
-class LLAudioStreamManagerFMODEX
-{
-public:
- LLAudioStreamManagerFMODEX(FMOD::System *system, const std::string& url);
- FMOD::Channel* startStream();
- bool stopStream(); // Returns true if the stream was successfully stopped.
- bool ready();
-
- const std::string& getURL() { return mInternetStreamURL; }
-
- FMOD_RESULT getOpenState(FMOD_OPENSTATE& openstate, unsigned int* percentbuffered=NULL, bool* starving=NULL, bool* diskbusy=NULL);
-protected:
- FMOD::System* mSystem;
- FMOD::Channel* mStreamChannel;
- FMOD::Sound* mInternetStream;
- bool mReady;
-
- std::string mInternetStreamURL;
-};
-
-
-
-//---------------------------------------------------------------------------
-// Internet Streaming
-//---------------------------------------------------------------------------
-LLStreamingAudio_FMODEX::LLStreamingAudio_FMODEX(FMOD::System *system) :
- mSystem(system),
- mCurrentInternetStreamp(NULL),
- mFMODInternetStreamChannelp(NULL),
- mGain(1.0f),
- mMetaData(NULL)
-{
- FMOD_RESULT result;
-
- // Number of milliseconds of audio to buffer for the audio card.
- // Must be larger than the usual Second Life frame stutter time.
- const U32 buffer_seconds = 10; //sec
- const U32 estimated_bitrate = 128; //kbit/sec
- result = mSystem->setStreamBufferSize(estimated_bitrate * buffer_seconds * 128/*bytes/kbit*/, FMOD_TIMEUNIT_RAWBYTES);
- Check_FMOD_Error(result, "FMOD::System::setStreamBufferSize");
-
- // Here's where we set the size of the network buffer and some buffering
- // parameters. In this case we want a network buffer of 16k, we want it
- // to prebuffer 40% of that when we first connect, and we want it
- // to rebuffer 80% of that whenever we encounter a buffer underrun.
-
- // Leave the net buffer properties at the default.
- //FSOUND_Stream_Net_SetBufferProperties(20000, 40, 80);
-}
-
-
-LLStreamingAudio_FMODEX::~LLStreamingAudio_FMODEX()
-{
- stop();
- for (U32 i = 0; i < 100; ++i)
- {
- if (releaseDeadStreams())
- break;
- ms_sleep(10);
- }
-}
-
-
-void LLStreamingAudio_FMODEX::start(const std::string& url)
-{
- //if (!mInited)
- //{
- // LL_WARNS() << "startInternetStream before audio initialized" << LL_ENDL;
- // return;
- //}
-
- // "stop" stream but don't clear url, etc. in case url == mInternetStreamURL
- stop();
-
- if (!url.empty())
- {
- if(mDeadStreams.empty())
- {
- LL_INFOS() << "Starting internet stream: " << url << LL_ENDL;
- mCurrentInternetStreamp = new LLAudioStreamManagerFMODEX(mSystem,url);
- mURL = url;
- mMetaData = new LLSD;
- }
- else
- {
- LL_INFOS() << "Deferring stream load until buffer release: " << url << LL_ENDL;
- mPendingURL = url;
- }
- }
- else
- {
- LL_INFOS() << "Set internet stream to null" << LL_ENDL;
- mURL.clear();
- }
-}
-
-enum utf_endian_type_t
-{
- UTF16LE,
- UTF16BE,
- UTF16
-};
-
-std::string utf16input_to_utf8(unsigned char* input, U32 len, utf_endian_type_t type)
-{
- if (type == UTF16)
- {
- type = UTF16BE; //Default
- if (len > 2)
- {
- //Parse and strip BOM.
- if ((input[0] == 0xFE && input[1] == 0xFF) ||
- (input[0] == 0xFF && input[1] == 0xFE))
- {
- input += 2;
- len -= 2;
- type = input[0] == 0xFE ? UTF16BE : UTF16LE;
- }
- }
- }
- llutf16string out_16((U16*)input, len / 2);
- if (len % 2)
- {
- out_16.push_back((input)[len - 1] << 8);
- }
- if (type == UTF16BE)
- {
- for (llutf16string::iterator i = out_16.begin(); i < out_16.end(); ++i)
- {
- llutf16string::value_type v = *i;
- *i = ((v & 0x00FF) << 8) | ((v & 0xFF00) >> 8);
- }
- }
- return utf16str_to_utf8str(out_16);
-}
-
-void LLStreamingAudio_FMODEX::update()
-{
- if (!releaseDeadStreams())
- {
- llassert_always(mCurrentInternetStreamp == NULL);
- return;
- }
-
- if(!mPendingURL.empty())
- {
- llassert_always(mCurrentInternetStreamp == NULL);
- LL_INFOS() << "Starting internet stream: " << mPendingURL << LL_ENDL;
- mCurrentInternetStreamp = new LLAudioStreamManagerFMODEX(mSystem,mPendingURL);
- mURL = mPendingURL;
- mMetaData = new LLSD;
- mPendingURL.clear();
- }
-
- // Don't do anything if there are no streams playing
- if (!mCurrentInternetStreamp)
- {
- return;
- }
-
- unsigned int progress;
- bool starving;
- bool diskbusy;
- FMOD_OPENSTATE open_state;
- FMOD_RESULT res = mCurrentInternetStreamp->getOpenState(open_state, &progress, &starving, &diskbusy);
-
- if (res != FMOD_OK || open_state == FMOD_OPENSTATE_ERROR)
- {
- stop();
- return;
- }
- else if (open_state == FMOD_OPENSTATE_READY)
- {
- // Stream is live
-
- // start the stream if it's ready
- if (!mFMODInternetStreamChannelp &&
- (mFMODInternetStreamChannelp = mCurrentInternetStreamp->startStream()))
- {
- // Reset volume to previously set volume
- setGain(getGain());
- Check_FMOD_Error(mFMODInternetStreamChannelp->setPaused(false), "FMOD::Channel::setPaused");
- }
- }
-
- if(mFMODInternetStreamChannelp)
- {
- if(!mMetaData)
- mMetaData = new LLSD;
-
- FMOD::Sound *sound = NULL;
-
- if(mFMODInternetStreamChannelp->getCurrentSound(&sound) == FMOD_OK && sound)
- {
- FMOD_TAG tag;
- S32 tagcount, dirtytagcount;
- if(sound->getNumTags(&tagcount, &dirtytagcount) == FMOD_OK && dirtytagcount)
- {
- mMetaData->clear();
-
- for(S32 i = 0; i < tagcount; ++i)
- {
- if(sound->getTag(NULL, i, &tag)!=FMOD_OK)
- continue;
- std::string name = tag.name;
- switch(tag.type) //Crappy tag translate table.
- {
- case(FMOD_TAGTYPE_ID3V2):
- if (!LLStringUtil::compareInsensitive(name, "TIT2")) name = "TITLE";
- else if(name == "TPE1") name = "ARTIST";
- break;
- case(FMOD_TAGTYPE_ASF):
- if (!LLStringUtil::compareInsensitive(name, "Title")) name = "TITLE";
- else if (!LLStringUtil::compareInsensitive(name, "WM/AlbumArtist")) name = "ARTIST";
- break;
- case(FMOD_TAGTYPE_FMOD):
- if (!LLStringUtil::compareInsensitive(name, "Sample Rate Change"))
- {
- LL_INFOS() << "Stream forced changing sample rate to " << *((float *)tag.data) << LL_ENDL;
- Check_FMOD_Error(mFMODInternetStreamChannelp->setFrequency(*((float *)tag.data)), "FMOD::Channel::setFrequency");
- }
- continue;
- default:
- if (!LLStringUtil::compareInsensitive(name, "TITLE") ||
- !LLStringUtil::compareInsensitive(name, "ARTIST"))
- LLStringUtil::toUpper(name);
- break;
- }
-
- switch(tag.datatype)
- {
- case(FMOD_TAGDATATYPE_INT):
- (*mMetaData)[name]=*(LLSD::Integer*)(tag.data);
- LL_INFOS() << tag.name << ": " << *(int*)(tag.data) << LL_ENDL;
- break;
- case(FMOD_TAGDATATYPE_FLOAT):
- (*mMetaData)[name]=*(LLSD::Float*)(tag.data);
- LL_INFOS() << tag.name << ": " << *(float*)(tag.data) << LL_ENDL;
- break;
- case(FMOD_TAGDATATYPE_STRING):
- {
- std::string out = rawstr_to_utf8(std::string((char*)tag.data,tag.datalen));
- if (out.length() && out[out.size() - 1] == 0)
- out.erase(out.size() - 1);
- (*mMetaData)[name]=out;
- LL_INFOS() << tag.name << "(RAW): " << out << LL_ENDL;
- }
- break;
- case(FMOD_TAGDATATYPE_STRING_UTF8) :
- {
- U8 offs = 0;
- if (tag.datalen > 3 && ((unsigned char*)tag.data)[0] == 0xEF && ((char*)tag.data)[1] == 0xBB && ((char*)tag.data)[2] == 0xBF)
- offs = 3;
- std::string out((char*)tag.data + offs, tag.datalen - offs);
- if (out.length() && out[out.size() - 1] == 0)
- out.erase(out.size() - 1);
- (*mMetaData)[name] = out;
- LL_INFOS() << tag.name << "(UTF8): " << out << LL_ENDL;
- }
- break;
- case(FMOD_TAGDATATYPE_STRING_UTF16):
- {
- std::string out = utf16input_to_utf8((unsigned char*)tag.data, tag.datalen, UTF16);
- if (out.length() && out[out.size() - 1] == 0)
- out.erase(out.size() - 1);
- (*mMetaData)[name] = out;
- LL_INFOS() << tag.name << "(UTF16): " << out << LL_ENDL;
- }
- break;
- case(FMOD_TAGDATATYPE_STRING_UTF16BE):
- {
- std::string out = utf16input_to_utf8((unsigned char*)tag.data, tag.datalen, UTF16BE);
- if (out.length() && out[out.size() - 1] == 0)
- out.erase(out.size() - 1);
- (*mMetaData)[name] = out;
- LL_INFOS() << tag.name << "(UTF16BE): " << out << LL_ENDL;
- }
- default:
- break;
- }
- }
- }
- if(starving)
- {
- bool paused = false;
- if (mFMODInternetStreamChannelp->getPaused(&paused) == FMOD_OK && !paused)
- {
- LL_INFOS() << "Stream starvation detected! Pausing stream until buffer nearly full." << LL_ENDL;
- LL_INFOS() << " (diskbusy="<setPaused(true), "FMOD::Channel::setPaused");
- }
- }
- else if(progress > 80)
- {
- Check_FMOD_Error(mFMODInternetStreamChannelp->setPaused(false), "FMOD::Channel::setPaused");
- }
- }
- }
-}
-
-void LLStreamingAudio_FMODEX::stop()
-{
- mPendingURL.clear();
-
- if(mMetaData)
- {
- delete mMetaData;
- mMetaData = NULL;
- }
- if (mFMODInternetStreamChannelp)
- {
- Check_FMOD_Error(mFMODInternetStreamChannelp->setPaused(true), "FMOD::Channel::setPaused");
- Check_FMOD_Error(mFMODInternetStreamChannelp->setPriority(0), "FMOD::Channel::setPriority");
- mFMODInternetStreamChannelp = NULL;
- }
-
- if (mCurrentInternetStreamp)
- {
- LL_INFOS() << "Stopping internet stream: " << mCurrentInternetStreamp->getURL() << LL_ENDL;
- if (mCurrentInternetStreamp->stopStream())
- {
- delete mCurrentInternetStreamp;
- }
- else
- {
- LL_WARNS() << "Pushing stream to dead list: " << mCurrentInternetStreamp->getURL() << LL_ENDL;
- mDeadStreams.push_back(mCurrentInternetStreamp);
- }
- mCurrentInternetStreamp = NULL;
- //mURL.clear();
- }
-}
-
-void LLStreamingAudio_FMODEX::pause(int pauseopt)
-{
- if (pauseopt < 0)
- {
- pauseopt = mCurrentInternetStreamp ? 1 : 0;
- }
-
- if (pauseopt)
- {
- if (mCurrentInternetStreamp)
- {
- stop();
- }
- }
- else
- {
- start(getURL());
- }
-}
-
-
-// A stream is "playing" if it has been requested to start. That
-// doesn't necessarily mean audio is coming out of the speakers.
-int LLStreamingAudio_FMODEX::isPlaying()
-{
- if (mCurrentInternetStreamp)
- {
- return 1; // Active and playing
- }
- else if (!mURL.empty() || !mPendingURL.empty())
- {
- return 2; // "Paused"
- }
- else
- {
- return 0;
- }
-}
-
-
-F32 LLStreamingAudio_FMODEX::getGain()
-{
- return mGain;
-}
-
-
-std::string LLStreamingAudio_FMODEX::getURL()
-{
- return mURL;
-}
-
-
-void LLStreamingAudio_FMODEX::setGain(F32 vol)
-{
- mGain = vol;
-
- if (mFMODInternetStreamChannelp)
- {
- vol = llclamp(vol * vol, 0.f, 1.f); //should vol be squared here?
-
- Check_FMOD_Error(mFMODInternetStreamChannelp->setVolume(vol), "FMOD::Channel::setVolume");
- }
-}
-
-/*virtual*/ bool LLStreamingAudio_FMODEX::getWaveData(float* arr, S32 count, S32 stride/*=1*/)
-{
- if(!mFMODInternetStreamChannelp || !mCurrentInternetStreamp)
- return false;
-
- bool muted=false;
- FMOD_RESULT res = mFMODInternetStreamChannelp->getMute(&muted);
- if(res != FMOD_OK || muted)
- return false;
-
- static std::vector local_array(count); //Have to have an extra buffer to mix channels. Bleh.
- if(count > (S32)local_array.size()) //Expand the array if needed. Try to minimize allocation calls, so don't ever shrink.
- local_array.resize(count);
-
- if( mFMODInternetStreamChannelp->getWaveData(&local_array[0],count,0) == FMOD_OK &&
- mFMODInternetStreamChannelp->getWaveData(&arr[0],count,1) == FMOD_OK )
- {
- for(S32 i = count-1;i>=0;i-=stride)
- {
- arr[i] += local_array[i];
- arr[i] *= .5f;
- }
- return true;
- }
- return false;
-}
-
-///////////////////////////////////////////////////////
-// manager of possibly-multiple internet audio streams
-
-LLAudioStreamManagerFMODEX::LLAudioStreamManagerFMODEX(FMOD::System *system, const std::string& url) :
- mSystem(system),
- mStreamChannel(NULL),
- mInternetStream(NULL),
- mReady(false)
-{
- mInternetStreamURL = url;
-
- /*FMOD_CREATESOUNDEXINFO exinfo;
- memset(&exinfo,0,sizeof(exinfo));
- exinfo.cbsize = sizeof(exinfo);
- exinfo.suggestedsoundtype = FMOD_SOUND_TYPE_OGGVORBIS; //Hint to speed up loading.*/
-
- FMOD_RESULT result = mSystem->createStream(url.c_str(), FMOD_2D | FMOD_NONBLOCKING | FMOD_IGNORETAGS, 0, &mInternetStream);
-
- if (result!= FMOD_OK)
- {
- LL_WARNS() << "Couldn't open fmod stream, error "
- << FMOD_ErrorString(result)
- << LL_ENDL;
- mReady = false;
- return;
- }
-
- mReady = true;
-}
-
-FMOD::Channel *LLAudioStreamManagerFMODEX::startStream()
-{
- // We need a live and opened stream before we try and play it.
- FMOD_OPENSTATE open_state;
- if (getOpenState(open_state) != FMOD_OK || open_state != FMOD_OPENSTATE_READY)
- {
- LL_WARNS() << "No internet stream to start playing!" << LL_ENDL;
- return NULL;
- }
-
- if(mStreamChannel)
- return mStreamChannel; //Already have a channel for this stream.
-
- Check_FMOD_Error(mSystem->playSound(FMOD_CHANNEL_FREE, mInternetStream, true, &mStreamChannel), "FMOD::System::playSound");
- return mStreamChannel;
-}
-
-bool LLAudioStreamManagerFMODEX::stopStream()
-{
- if (mInternetStream)
- {
- bool close = true;
- FMOD_OPENSTATE open_state;
- if (getOpenState(open_state) == FMOD_OK)
- {
- switch (open_state)
- {
- case FMOD_OPENSTATE_CONNECTING:
- close = false;
- break;
- default:
- close = true;
- }
- }
-
- if (close && mInternetStream->release() == FMOD_OK)
- {
- mStreamChannel = NULL;
- mInternetStream = NULL;
- return true;
- }
- else
- {
- return false;
- }
- }
- else
- {
- return true;
- }
-}
-
-FMOD_RESULT LLAudioStreamManagerFMODEX::getOpenState(FMOD_OPENSTATE& state, unsigned int* percentbuffered, bool* starving, bool* diskbusy)
-{
- if (!mInternetStream)
- return FMOD_ERR_INVALID_HANDLE;
- FMOD_RESULT result = mInternetStream->getOpenState(&state, percentbuffered, starving, diskbusy);
- Check_FMOD_Error(result, "FMOD::Sound::getOpenState");
- return result;
-}
-
-void LLStreamingAudio_FMODEX::setBufferSizes(U32 streambuffertime, U32 decodebuffertime)
-{
- Check_FMOD_Error(mSystem->setStreamBufferSize(streambuffertime / 1000 * 128 * 128, FMOD_TIMEUNIT_RAWBYTES), "FMOD::System::setStreamBufferSize");
- FMOD_ADVANCEDSETTINGS settings;
- memset(&settings,0,sizeof(settings));
- settings.cbsize=sizeof(settings);
- settings.defaultDecodeBufferSize = decodebuffertime;//ms
- Check_FMOD_Error(mSystem->setAdvancedSettings(&settings), "FMOD::System::setAdvancedSettings");
-}
-
-bool LLStreamingAudio_FMODEX::releaseDeadStreams()
-{
- // Kill dead internet streams, if possible
- std::list::iterator iter;
- for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();)
- {
- LLAudioStreamManagerFMODEX *streamp = *iter;
- if (streamp->stopStream())
- {
- LL_INFOS() << "Closed dead stream" << LL_ENDL;
- delete streamp;
- mDeadStreams.erase(iter++);
- }
- else
- {
- iter++;
- }
- }
-
- return mDeadStreams.empty();
-}
\ No newline at end of file
diff --git a/indra/llaudio/llstreamingaudio_fmodex.h b/indra/llaudio/llstreamingaudio_fmodex.h
deleted file mode 100644
index 15a4af9314..0000000000
--- a/indra/llaudio/llstreamingaudio_fmodex.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/**
- * @file streamingaudio_fmod.h
- * @author Tofu Linden
- * @brief Definition of LLStreamingAudio_FMOD implementation
- *
- * $LicenseInfo:firstyear=2009&license=viewergpl$
- *
- * Copyright (c) 2009, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-#ifndef LL_STREAMINGAUDIO_FMOD_H
-#define LL_STREAMINGAUDIO_FMOD_H
-
-#include "stdtypes.h" // from llcommon
-
-#include "llstreamingaudio.h"
-#include "lltimer.h"
-
-//Stubs
-class LLAudioStreamManagerFMODEX;
-namespace FMOD
-{
- class System;
- class Channel;
-}
-
-//Interfaces
-class LLStreamingAudio_FMODEX : public LLStreamingAudioInterface
-{
- public:
- LLStreamingAudio_FMODEX(FMOD::System *system);
- /*virtual*/ ~LLStreamingAudio_FMODEX();
-
- /*virtual*/ void start(const std::string& url);
- /*virtual*/ void stop();
- /*virtual*/ void pause(int pause);
- /*virtual*/ void update();
- /*virtual*/ int isPlaying();
- /*virtual*/ void setGain(F32 vol);
- /*virtual*/ F32 getGain();
- /*virtual*/ std::string getURL();
-
- /*virtual*/ bool supportsMetaData(){return true;}
- /*virtual*/ const LLSD *getMetaData(){return mMetaData;} //return NULL if not playing.
- /*virtual*/ bool supportsWaveData(){return true;}
- /*virtual*/ bool getWaveData(float* arr, S32 count, S32 stride = 1);
- /*virtual*/ bool supportsAdjustableBufferSizes(){return true;}
- /*virtual*/ void setBufferSizes(U32 streambuffertime, U32 decodebuffertime);
-private:
- bool releaseDeadStreams();
-
- FMOD::System *mSystem;
-
- LLAudioStreamManagerFMODEX *mCurrentInternetStreamp;
- FMOD::Channel *mFMODInternetStreamChannelp;
- std::list mDeadStreams;
-
- std::string mURL;
- std::string mPendingURL;
- F32 mGain;
-
- LLSD *mMetaData;
-};
-
-
-#endif // LL_STREAMINGAUDIO_FMOD_H
diff --git a/indra/llaudio/llstreamingaudio_fmodstudio.cpp b/indra/llaudio/llstreamingaudio_fmodstudio.cpp
index 5ef93fd008..d7c6b48b78 100644
--- a/indra/llaudio/llstreamingaudio_fmodstudio.cpp
+++ b/indra/llaudio/llstreamingaudio_fmodstudio.cpp
@@ -31,6 +31,7 @@
*/
#include "linden_common.h"
+#include "llstreamingaudio_fmodstudio.h"
#include "llmath.h"
#include "llthread.h"
@@ -38,8 +39,6 @@
#include "fmod.hpp"
#include "fmod_errors.h"
-#include "llstreamingaudio_fmodstudio.h"
-
inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string)
{
if (result == FMOD_OK)
@@ -61,9 +60,9 @@ class LLAudioStreamManagerFMODSTUDIO
FMOD_RESULT getOpenState(FMOD_OPENSTATE& openstate, unsigned int* percentbuffered = NULL, bool* starving = NULL, bool* diskbusy = NULL);
protected:
FMOD::System* mSystem;
+ FMOD::ChannelGroup* mChannelGroup;
FMOD::Channel* mStreamChannel;
FMOD::Sound* mInternetStream;
- FMOD::ChannelGroup* mChannelGroup;
bool mReady;
std::string mInternetStreamURL;
@@ -119,11 +118,11 @@ FMOD_RESULT F_CALLBACK waveDataCallback(FMOD_DSP_STATE *dsp_state, float *inbuff
LLStreamingAudio_FMODSTUDIO::LLStreamingAudio_FMODSTUDIO(FMOD::System *system) :
mSystem(system),
mCurrentInternetStreamp(NULL),
+ mStreamDSP(NULL),
+ mStreamGroup(NULL),
mFMODInternetStreamChannelp(NULL),
mGain(1.0f),
- mMetaData(NULL),
- mStreamGroup(NULL),
- mStreamDSP(NULL)
+ mMetaData(NULL)
{
FMOD_RESULT result;
@@ -142,10 +141,9 @@ LLStreamingAudio_FMODSTUDIO::LLStreamingAudio_FMODSTUDIO(FMOD::System *system) :
// Leave the net buffer properties at the default.
//FSOUND_Stream_Net_SetBufferProperties(20000, 40, 80);
- Check_FMOD_Error(mSystem->createChannelGroup("stream", &mStreamGroup), "FMOD::System::createChannelGroup");
+ Check_FMOD_Error(system->createChannelGroup("stream", &mStreamGroup), "FMOD::System::createChannelGroup");
- FMOD_DSP_DESCRIPTION dspdesc;
- memset(&dspdesc, 0, sizeof(FMOD_DSP_DESCRIPTION)); //Zero out everything
+ FMOD_DSP_DESCRIPTION dspdesc = { };
dspdesc.pluginsdkversion = FMOD_PLUGIN_SDK_VERSION;
strncpy(dspdesc.name, "Waveform", sizeof(dspdesc.name));
dspdesc.numoutputbuffers = 1;
@@ -154,7 +152,6 @@ LLStreamingAudio_FMODSTUDIO::LLStreamingAudio_FMODSTUDIO(FMOD::System *system) :
Check_FMOD_Error(system->createDSP(&dspdesc, &mStreamDSP), "FMOD::System::createDSP");
}
-
LLStreamingAudio_FMODSTUDIO::~LLStreamingAudio_FMODSTUDIO()
{
stop();
@@ -168,7 +165,6 @@ LLStreamingAudio_FMODSTUDIO::~LLStreamingAudio_FMODSTUDIO()
cleanupWaveData();
}
-
void LLStreamingAudio_FMODSTUDIO::start(const std::string& url)
{
//if (!mInited)
@@ -209,7 +205,7 @@ enum utf_endian_type_t
UTF16
};
-std::string utf16input_to_utf8(char* input, U32 len, utf_endian_type_t type)
+std::string utf16input_to_utf8(unsigned char* input, U32 len, utf_endian_type_t type)
{
if (type == UTF16)
{
@@ -226,7 +222,7 @@ std::string utf16input_to_utf8(char* input, U32 len, utf_endian_type_t type)
}
}
}
- llutf16string out_16((U16*)input, len / 2);
+ llutf16string out_16((llutf16string::value_type*)input, len / 2);
if (len % 2)
{
out_16.push_back((input)[len - 1] << 8);
@@ -254,7 +250,7 @@ void LLStreamingAudio_FMODSTUDIO::update()
{
llassert_always(mCurrentInternetStreamp == NULL);
LL_INFOS() << "Starting internet stream: " << mPendingURL << LL_ENDL;
- mCurrentInternetStreamp = new LLAudioStreamManagerFMODSTUDIO(mSystem,mStreamGroup, mPendingURL);
+ mCurrentInternetStreamp = new LLAudioStreamManagerFMODSTUDIO(mSystem, mStreamGroup, mPendingURL);
mURL = mPendingURL;
mMetaData = new LLSD;
mPendingURL.clear();
@@ -315,6 +311,7 @@ void LLStreamingAudio_FMODSTUDIO::update()
{
if(sound->getTag(NULL, i, &tag)!=FMOD_OK)
continue;
+
std::string name = tag.name;
switch(tag.type) //Crappy tag translate table.
{
@@ -373,7 +370,7 @@ void LLStreamingAudio_FMODSTUDIO::update()
break;
case(FMOD_TAGDATATYPE_STRING_UTF16):
{
- std::string out = utf16input_to_utf8((char*)tag.data, tag.datalen, UTF16);
+ std::string out = utf16input_to_utf8((unsigned char*)tag.data, tag.datalen, UTF16);
if (out.length() && out[out.size() - 1] == 0)
out.erase(out.size() - 1);
(*mMetaData)[name] = out;
@@ -382,7 +379,7 @@ void LLStreamingAudio_FMODSTUDIO::update()
break;
case(FMOD_TAGDATATYPE_STRING_UTF16BE):
{
- std::string out = utf16input_to_utf8((char*)tag.data, tag.datalen, UTF16BE);
+ std::string out = utf16input_to_utf8((unsigned char*)tag.data, tag.datalen, UTF16BE);
if (out.length() && out[out.size() - 1] == 0)
out.erase(out.size() - 1);
(*mMetaData)[name] = out;
@@ -393,6 +390,7 @@ void LLStreamingAudio_FMODSTUDIO::update()
}
}
}
+ static bool was_starved = false;
if(starving)
{
bool paused = false;
@@ -403,9 +401,11 @@ void LLStreamingAudio_FMODSTUDIO::update()
LL_INFOS() << " (progress="<
- LL_WARNS() << "joint not found: " << joint_name << LL_ENDL;
+ LL_WARNS() << "invalid joint name: " << joint_name
+ << " for animation " << asset_id << LL_ENDL;
//return FALSE;
}
@@ -1561,13 +1328,15 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
S32 joint_priority;
if (!dp.unpackS32(joint_priority, "joint_priority"))
{
- LL_WARNS() << "can't read joint priority." << LL_ENDL;
+ LL_WARNS() << "can't read joint priority."
+ << " for animation " << asset_id << LL_ENDL;
return FALSE;
}
if (joint_priority < LLJoint::USE_MOTION_PRIORITY)
{
- LL_WARNS() << "joint priority unknown - too low." << LL_ENDL;
+ LL_WARNS() << "joint priority unknown - too low."
+ << " for animation " << asset_id << LL_ENDL;
return FALSE;
}
@@ -1585,7 +1354,8 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
//---------------------------------------------------------------------
if (!dp.unpackS32(joint_motion->mRotationCurve.mNumKeys, "num_rot_keys") || joint_motion->mRotationCurve.mNumKeys < 0)
{
- LL_WARNS() << "can't read number of rotation keys" << LL_ENDL;
+ LL_WARNS() << "can't read number of rotation keys"
+ << " for animation " << asset_id << LL_ENDL;
return FALSE;
}
@@ -1608,9 +1378,10 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
if (old_version)
{
if (!dp.unpackF32(time, "time") ||
- !llfinite(time))
+ !std::isfinite(time))
{
- LL_WARNS() << "can't read rotation key (" << k << ")" << LL_ENDL;
+ LL_WARNS() << "can't read rotation key (" << k << ")"
+ << " for animation " << asset_id << LL_ENDL;
return FALSE;
}
@@ -1619,7 +1390,8 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
{
if (!dp.unpackU16(time_short, "time"))
{
- LL_WARNS() << "can't read rotation key (" << k << ")" << LL_ENDL;
+ LL_WARNS() << "can't read rotation key (" << k << ")"
+ << " for animation " << asset_id << LL_ENDL;
return FALSE;
}
@@ -1627,7 +1399,8 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
if (time < 0 || time > mJointMotionList->mDuration)
{
- LL_WARNS() << "invalid frame time" << LL_ENDL;
+ LL_WARNS() << "invalid frame time"
+ << " for animation " << asset_id << LL_ENDL;
return FALSE;
}
}
@@ -1644,7 +1417,7 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
success = dp.unpackVector3(rot_angles, "rot_angles") && rot_angles.isFinite();
LLQuaternion::Order ro = StringToOrder("ZYX");
- rot_key.mRotation = mayaQ(rot_angles.mV[VX], rot_angles.mV[VY], rot_angles.mV[VZ], ro);
+ rot_key.mValue = mayaQ(rot_angles.mV[VX], rot_angles.mV[VY], rot_angles.mV[VZ], ro);
}
else
{
@@ -1656,30 +1429,35 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
rot_vec.mV[VX] = U16_to_F32(x, -1.f, 1.f);
rot_vec.mV[VY] = U16_to_F32(y, -1.f, 1.f);
rot_vec.mV[VZ] = U16_to_F32(z, -1.f, 1.f);
- rot_key.mRotation.unpackFromVector3(rot_vec);
+ rot_key.mValue.unpackFromVector3(rot_vec);
}
- if( !(rot_key.mRotation.isFinite()) )
+ if( !(rot_key.mValue.isFinite()) )
{
- LL_WARNS() << "non-finite angle in rotation key" << LL_ENDL;
+ LL_WARNS() << "non-finite angle in rotation key"
+ << " for animation " << asset_id << LL_ENDL;
success = FALSE;
}
if (!success)
{
- LL_WARNS() << "can't read rotation key (" << k << ")" << LL_ENDL;
+ LL_WARNS() << "can't read rotation key (" << k << ")"
+ << " for animation " << asset_id << LL_ENDL;
return FALSE;
}
- rCurve->mKeys[time] = rot_key;
+ rCurve->mKeys.emplace_back(time, rot_key);
}
+ std::sort(rCurve->mKeys.begin(), rCurve->mKeys.end(), [](const auto& a, const auto& b) { return a.first < b.first; });
+
//---------------------------------------------------------------------
// scan position curve header
//---------------------------------------------------------------------
if (!dp.unpackS32(joint_motion->mPositionCurve.mNumKeys, "num_pos_keys") || joint_motion->mPositionCurve.mNumKeys < 0)
{
- LL_WARNS() << "can't read number of position keys" << LL_ENDL;
+ LL_WARNS() << "can't read number of position keys"
+ << " for animation " << asset_id << LL_ENDL;
return FALSE;
}
@@ -1702,9 +1480,10 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
if (old_version)
{
if (!dp.unpackF32(pos_key.mTime, "time") ||
- !llfinite(pos_key.mTime))
+ !std::isfinite(pos_key.mTime))
{
- LL_WARNS() << "can't read position key (" << k << ")" << LL_ENDL;
+ LL_WARNS() << "can't read position key (" << k << ")"
+ << " for animation " << asset_id << LL_ENDL;
return FALSE;
}
}
@@ -1712,7 +1491,8 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
{
if (!dp.unpackU16(time_short, "time"))
{
- LL_WARNS() << "can't read position key (" << k << ")" << LL_ENDL;
+ LL_WARNS() << "can't read position key (" << k << ")"
+ << " for animation " << asset_id << LL_ENDL;
return FALSE;
}
@@ -1723,7 +1503,13 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
if (old_version)
{
- success = dp.unpackVector3(pos_key.mPosition, "pos");
+ success = dp.unpackVector3(pos_key.mValue, "pos");
+
+ //MAINT-6162
+ pos_key.mValue.mV[VX] = llclamp( pos_key.mValue.mV[VX], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
+ pos_key.mValue.mV[VY] = llclamp( pos_key.mValue.mV[VY], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
+ pos_key.mValue.mV[VZ] = llclamp( pos_key.mValue.mV[VZ], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
+
}
else
{
@@ -1733,31 +1519,36 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
success &= dp.unpackU16(y, "pos_y");
success &= dp.unpackU16(z, "pos_z");
- pos_key.mPosition.mV[VX] = U16_to_F32(x, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
- pos_key.mPosition.mV[VY] = U16_to_F32(y, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
- pos_key.mPosition.mV[VZ] = U16_to_F32(z, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
+ pos_key.mValue.mV[VX] = U16_to_F32(x, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
+ pos_key.mValue.mV[VY] = U16_to_F32(y, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
+ pos_key.mValue.mV[VZ] = U16_to_F32(z, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
}
- if( !(pos_key.mPosition.isFinite()) )
+ if( !(pos_key.mValue.isFinite()) )
{
- LL_WARNS() << "non-finite position in key" << LL_ENDL;
+ LL_WARNS() << "non-finite position in key"
+ << " for animation " << asset_id << LL_ENDL;
success = FALSE;
}
if (!success)
{
- LL_WARNS() << "can't read position key (" << k << ")" << LL_ENDL;
+ LL_WARNS() << "can't read position key (" << k << ")"
+ << " for animation " << asset_id << LL_ENDL;
return FALSE;
}
- pCurve->mKeys[pos_key.mTime] = pos_key;
+ pCurve->mKeys.emplace_back(pos_key.mTime, pos_key);
if (is_pelvis)
{
- mJointMotionList->mPelvisBBox.addPoint(pos_key.mPosition);
+ mJointMotionList->mPelvisBBox.addPoint(pos_key.mValue);
}
+
}
+ std::sort(pCurve->mKeys.begin(), pCurve->mKeys.end(), [](const auto& a, const auto& b) { return a.first < b.first; });
+
joint_motion->mUsage = joint_state->getUsage();
}
@@ -1767,13 +1558,15 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
S32 num_constraints = 0;
if (!dp.unpackS32(num_constraints, "num_constraints"))
{
- LL_WARNS() << "can't read number of constraints" << LL_ENDL;
+ LL_WARNS() << "can't read number of constraints"
+ << " for animation " << asset_id << LL_ENDL;
return FALSE;
}
if (num_constraints > MAX_CONSTRAINTS || num_constraints < 0)
{
- LL_WARNS() << "Bad number of constraints... ignoring: " << num_constraints << LL_ENDL;
+ LL_WARNS() << "Bad number of constraints... ignoring: " << num_constraints
+ << " for animation " << asset_id << LL_ENDL;
}
else
{
@@ -1784,35 +1577,36 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
for(S32 i = 0; i < num_constraints; ++i)
{
// read in constraint data
- JointConstraintSharedData* constraintp = new JointConstraintSharedData;
+ auto constraintp = new JointConstraintSharedData;
+ std::unique_ptr watcher(constraintp);
U8 byte = 0;
if (!dp.unpackU8(byte, "chain_length"))
{
- LL_WARNS() << "can't read constraint chain length" << LL_ENDL;
- delete constraintp;
+ LL_WARNS() << "can't read constraint chain length"
+ << " for animation " << asset_id << LL_ENDL;
return FALSE;
}
constraintp->mChainLength = (S32) byte;
if((U32)constraintp->mChainLength > mJointMotionList->getNumJointMotions())
{
- LL_WARNS() << "invalid constraint chain length" << LL_ENDL;
- delete constraintp;
+ LL_WARNS() << "invalid constraint chain length"
+ << " for animation " << asset_id << LL_ENDL;
return FALSE;
}
if (!dp.unpackU8(byte, "constraint_type"))
{
- LL_WARNS() << "can't read constraint type" << LL_ENDL;
- delete constraintp;
+ LL_WARNS() << "can't read constraint type"
+ << " for animation " << asset_id << LL_ENDL;
return FALSE;
}
if( byte >= NUM_CONSTRAINT_TYPES )
{
- LL_WARNS() << "invalid constraint type" << LL_ENDL;
- delete constraintp;
+ LL_WARNS() << "invalid constraint type"
+ << " for animation " << asset_id << LL_ENDL;
return FALSE;
}
constraintp->mConstraintType = (EConstraintType)byte;
@@ -1821,42 +1615,39 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
U8 bin_data[BIN_DATA_LENGTH+1];
if (!dp.unpackBinaryDataFixed(bin_data, BIN_DATA_LENGTH, "source_volume"))
{
- LL_WARNS() << "can't read source volume name" << LL_ENDL;
- delete constraintp;
+ LL_WARNS() << "can't read source volume name"
+ << " for animation " << asset_id << LL_ENDL;
return FALSE;
}
bin_data[BIN_DATA_LENGTH] = 0; // Ensure null termination
str = (char*)bin_data;
constraintp->mSourceConstraintVolume = mCharacter->getCollisionVolumeID(str);
-
- //
- if(constraintp->mSourceConstraintVolume == -1)
+ if (constraintp->mSourceConstraintVolume == -1)
{
- LL_WARNS() << "can't get source constraint volume" << LL_ENDL;
- delete constraintp;
+ LL_WARNS() << "not a valid source constraint volume " << str
+ << " for animation " << asset_id << LL_ENDL;
return FALSE;
}
- //
if (!dp.unpackVector3(constraintp->mSourceConstraintOffset, "source_offset"))
{
- LL_WARNS() << "can't read constraint source offset" << LL_ENDL;
- delete constraintp;
+ LL_WARNS() << "can't read constraint source offset"
+ << " for animation " << asset_id << LL_ENDL;
return FALSE;
}
if( !(constraintp->mSourceConstraintOffset.isFinite()) )
{
- LL_WARNS() << "non-finite constraint source offset" << LL_ENDL;
- delete constraintp;
+ LL_WARNS() << "non-finite constraint source offset"
+ << " for animation " << asset_id << LL_ENDL;
return FALSE;
}
if (!dp.unpackBinaryDataFixed(bin_data, BIN_DATA_LENGTH, "target_volume"))
{
- LL_WARNS() << "can't read target volume name" << LL_ENDL;
- delete constraintp;
+ LL_WARNS() << "can't read target volume name"
+ << " for animation " << asset_id << LL_ENDL;
return FALSE;
}
@@ -1871,33 +1662,39 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
{
constraintp->mConstraintTargetType = CONSTRAINT_TARGET_TYPE_BODY;
constraintp->mTargetConstraintVolume = mCharacter->getCollisionVolumeID(str);
+ if (constraintp->mTargetConstraintVolume == -1)
+ {
+ LL_WARNS() << "not a valid target constraint volume " << str
+ << " for animation " << asset_id << LL_ENDL;
+ return FALSE;
+ }
}
if (!dp.unpackVector3(constraintp->mTargetConstraintOffset, "target_offset"))
{
- LL_WARNS() << "can't read constraint target offset" << LL_ENDL;
- delete constraintp;
+ LL_WARNS() << "can't read constraint target offset"
+ << " for animation " << asset_id << LL_ENDL;
return FALSE;
}
if( !(constraintp->mTargetConstraintOffset.isFinite()) )
{
- LL_WARNS() << "non-finite constraint target offset" << LL_ENDL;
- delete constraintp;
+ LL_WARNS() << "non-finite constraint target offset"
+ << " for animation " << asset_id << LL_ENDL;
return FALSE;
}
if (!dp.unpackVector3(constraintp->mTargetConstraintDir, "target_dir"))
{
- LL_WARNS() << "can't read constraint target direction" << LL_ENDL;
- delete constraintp;
+ LL_WARNS() << "can't read constraint target direction"
+ << " for animation " << asset_id << LL_ENDL;
return FALSE;
}
if( !(constraintp->mTargetConstraintDir.isFinite()) )
{
- LL_WARNS() << "non-finite constraint target direction" << LL_ENDL;
- delete constraintp;
+ LL_WARNS() << "non-finite constraint target direction"
+ << " for animation " << asset_id << LL_ENDL;
return FALSE;
}
@@ -1907,45 +1704,40 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
// constraintp->mTargetConstraintDir *= constraintp->mSourceConstraintOffset.magVec();
}
- if (!dp.unpackF32(constraintp->mEaseInStartTime, "ease_in_start") || !llfinite(constraintp->mEaseInStartTime))
+ if (!dp.unpackF32(constraintp->mEaseInStartTime, "ease_in_start") || !std::isfinite(constraintp->mEaseInStartTime))
{
- LL_WARNS() << "can't read constraint ease in start time" << LL_ENDL;
- delete constraintp;
+ LL_WARNS() << "can't read constraint ease in start time"
+ << " for animation " << asset_id << LL_ENDL;
return FALSE;
}
- if (!dp.unpackF32(constraintp->mEaseInStopTime, "ease_in_stop") || !llfinite(constraintp->mEaseInStopTime))
+ if (!dp.unpackF32(constraintp->mEaseInStopTime, "ease_in_stop") || !std::isfinite(constraintp->mEaseInStopTime))
{
- LL_WARNS() << "can't read constraint ease in stop time" << LL_ENDL;
- delete constraintp;
+ LL_WARNS() << "can't read constraint ease in stop time"
+ << " for animation " << asset_id << LL_ENDL;
return FALSE;
}
- if (!dp.unpackF32(constraintp->mEaseOutStartTime, "ease_out_start") || !llfinite(constraintp->mEaseOutStartTime))
+ if (!dp.unpackF32(constraintp->mEaseOutStartTime, "ease_out_start") || !std::isfinite(constraintp->mEaseOutStartTime))
{
- LL_WARNS() << "can't read constraint ease out start time" << LL_ENDL;
- delete constraintp;
+ LL_WARNS() << "can't read constraint ease out start time"
+ << " for animation " << asset_id << LL_ENDL;
return FALSE;
}
- if (!dp.unpackF32(constraintp->mEaseOutStopTime, "ease_out_stop") || !llfinite(constraintp->mEaseOutStopTime))
+ if (!dp.unpackF32(constraintp->mEaseOutStopTime, "ease_out_stop") || !std::isfinite(constraintp->mEaseOutStopTime))
{
- LL_WARNS() << "can't read constraint ease out stop time" << LL_ENDL;
- delete constraintp;
+ LL_WARNS() << "can't read constraint ease out stop time"
+ << " for animation " << asset_id << LL_ENDL;
return FALSE;
}
- AIAutoDestruct watcher;
+ constraintp->mJointStateIndices = new S32[constraintp->mChainLength + 1]; // note: mChainLength is size-limited - comes from a byte
+
if (singu_new_joint_motion_list)
{
- mJointMotionList->mConstraints.push_front(constraintp);
+ mJointMotionList->mConstraints.push_front(watcher.release());
}
- else
- {
- watcher.add(constraintp);
- }
-
- constraintp->mJointStateIndices = new S32[constraintp->mChainLength + 1]; // note: mChainLength is size-limited - comes from a byte
LLJoint* joint = mCharacter->findCollisionVolume(constraintp->mSourceConstraintVolume);
// get joint to which this collision volume is attached
@@ -1959,7 +1751,8 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
if (!parent)
{
LL_WARNS() << "Joint with no parent: " << joint->getName()
- << " Emote: " << mJointMotionList->mEmoteName << LL_ENDL;
+ << " Emote: " << mJointMotionList->mEmoteName
+ << " for animation " << asset_id << LL_ENDL;
return FALSE;
}
joint = parent;
@@ -1970,7 +1763,8 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
if ( !constraint_joint )
{
- LL_WARNS() << "Invalid joint " << j << LL_ENDL;
+ LL_WARNS() << "Invalid joint " << j
+ << " for animation " << asset_id << LL_ENDL;
return FALSE;
}
@@ -1982,7 +1776,8 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
}
if (constraintp->mJointStateIndices[i] < 0 )
{
- LL_WARNS() << "No joint index for constraint " << i << LL_ENDL;
+ LL_WARNS() << "No joint index for constraint " << i
+ << " for animation " << asset_id << LL_ENDL;
return FALSE;
}
}
@@ -2003,6 +1798,8 @@ BOOL LLKeyframeMotion::serialize(LLDataPacker& dp) const
{
BOOL success = TRUE;
+ LL_DEBUGS("BVH") << "serializing" << LL_ENDL;
+
success &= dp.packU16(KEYFRAME_MOTION_VERSION, "version");
success &= dp.packU16(KEYFRAME_MOTION_SUBVERSION, "sub_version");
success &= dp.packS32(mJointMotionList->mBasePriority, "base_priority");
@@ -2016,6 +1813,19 @@ BOOL LLKeyframeMotion::serialize(LLDataPacker& dp) const
success &= dp.packU32(mJointMotionList->mHandPose, "hand_pose");
success &= dp.packU32(mJointMotionList->getNumJointMotions(), "num_joints");
+ LL_DEBUGS("BVH") << "version " << KEYFRAME_MOTION_VERSION << LL_ENDL;
+ LL_DEBUGS("BVH") << "sub_version " << KEYFRAME_MOTION_SUBVERSION << LL_ENDL;
+ LL_DEBUGS("BVH") << "base_priority " << mJointMotionList->mBasePriority << LL_ENDL;
+ LL_DEBUGS("BVH") << "duration " << mJointMotionList->mDuration << LL_ENDL;
+ LL_DEBUGS("BVH") << "emote_name " << mJointMotionList->mEmoteName << LL_ENDL;
+ LL_DEBUGS("BVH") << "loop_in_point " << mJointMotionList->mLoopInPoint << LL_ENDL;
+ LL_DEBUGS("BVH") << "loop_out_point " << mJointMotionList->mLoopOutPoint << LL_ENDL;
+ LL_DEBUGS("BVH") << "loop " << mJointMotionList->mLoop << LL_ENDL;
+ LL_DEBUGS("BVH") << "ease_in_duration " << mJointMotionList->mEaseInDuration << LL_ENDL;
+ LL_DEBUGS("BVH") << "ease_out_duration " << mJointMotionList->mEaseOutDuration << LL_ENDL;
+ LL_DEBUGS("BVH") << "hand_pose " << mJointMotionList->mHandPose << LL_ENDL;
+ LL_DEBUGS("BVH") << "num_joints " << mJointMotionList->getNumJointMotions() << LL_ENDL;
+
for (U32 i = 0; i < mJointMotionList->getNumJointMotions(); i++)
{
JointMotion* joint_motionp = mJointMotionList->getJointMotion(i);
@@ -2023,6 +1833,7 @@ BOOL LLKeyframeMotion::serialize(LLDataPacker& dp) const
success &= dp.packS32(joint_motionp->mPriority, "joint_priority");
success &= dp.packS32(joint_motionp->mRotationCurve.mNumKeys, "num_rot_keys");
+ LL_DEBUGS("BVH") << "Joint " << joint_motionp->mJointName << LL_ENDL;
for (RotationCurve::key_map_t::iterator iter = joint_motionp->mRotationCurve.mKeys.begin();
iter != joint_motionp->mRotationCurve.mKeys.end(); ++iter)
{
@@ -2030,7 +1841,7 @@ BOOL LLKeyframeMotion::serialize(LLDataPacker& dp) const
U16 time_short = F32_to_U16(rot_key.mTime, 0.f, mJointMotionList->mDuration);
success &= dp.packU16(time_short, "time");
- LLVector3 rot_angles = rot_key.mRotation.packToVector3();
+ LLVector3 rot_angles = rot_key.mValue.packToVector3();
U16 x, y, z;
rot_angles.quantize16(-1.f, 1.f, -1.f, 1.f);
@@ -2040,6 +1851,8 @@ BOOL LLKeyframeMotion::serialize(LLDataPacker& dp) const
success &= dp.packU16(x, "rot_angle_x");
success &= dp.packU16(y, "rot_angle_y");
success &= dp.packU16(z, "rot_angle_z");
+
+ LL_DEBUGS("BVH") << " rot: t " << rot_key.mTime << " angles " << rot_angles.mV[VX] <<","<< rot_angles.mV[VY] <<","<< rot_angles.mV[VZ] << LL_ENDL;
}
success &= dp.packS32(joint_motionp->mPositionCurve.mNumKeys, "num_pos_keys");
@@ -2051,44 +1864,61 @@ BOOL LLKeyframeMotion::serialize(LLDataPacker& dp) const
success &= dp.packU16(time_short, "time");
U16 x, y, z;
- pos_key.mPosition.quantize16(-LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
- x = F32_to_U16(pos_key.mPosition.mV[VX], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
- y = F32_to_U16(pos_key.mPosition.mV[VY], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
- z = F32_to_U16(pos_key.mPosition.mV[VZ], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
+ pos_key.mValue.quantize16(-LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
+ x = F32_to_U16(pos_key.mValue.mV[VX], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
+ y = F32_to_U16(pos_key.mValue.mV[VY], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
+ z = F32_to_U16(pos_key.mValue.mV[VZ], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET);
success &= dp.packU16(x, "pos_x");
success &= dp.packU16(y, "pos_y");
success &= dp.packU16(z, "pos_z");
+
+ LL_DEBUGS("BVH") << " pos: t " << pos_key.mTime << " pos " << pos_key.mValue.mV[VX] <<","<< pos_key.mValue.mV[VY] <<","<< pos_key.mValue.mV[VZ] << LL_ENDL;
}
}
success &= dp.packS32(mJointMotionList->mConstraints.size(), "num_constraints");
+ LL_DEBUGS("BVH") << "num_constraints " << mJointMotionList->mConstraints.size() << LL_ENDL;
for (JointMotionList::constraint_list_t::const_iterator iter = mJointMotionList->mConstraints.begin();
iter != mJointMotionList->mConstraints.end(); ++iter)
{
JointConstraintSharedData* shared_constraintp = *iter;
success &= dp.packU8(shared_constraintp->mChainLength, "chain_length");
success &= dp.packU8(shared_constraintp->mConstraintType, "constraint_type");
- char volume_name[16]; /* Flawfinder: ignore */
- snprintf(volume_name, sizeof(volume_name), "%s", /* Flawfinder: ignore */
+ char source_volume[16]; /* Flawfinder: ignore */
+ snprintf(source_volume, sizeof(source_volume), "%s", /* Flawfinder: ignore */
mCharacter->findCollisionVolume(shared_constraintp->mSourceConstraintVolume)->getName().c_str());
- success &= dp.packBinaryDataFixed((U8*)volume_name, 16, "source_volume");
+
+ success &= dp.packBinaryDataFixed((U8*)source_volume, 16, "source_volume");
success &= dp.packVector3(shared_constraintp->mSourceConstraintOffset, "source_offset");
+ char target_volume[16]; /* Flawfinder: ignore */
if (shared_constraintp->mConstraintTargetType == CONSTRAINT_TARGET_TYPE_GROUND)
{
- snprintf(volume_name,sizeof(volume_name), "%s", "GROUND"); /* Flawfinder: ignore */
+ snprintf(target_volume,sizeof(target_volume), "%s", "GROUND"); /* Flawfinder: ignore */
}
else
{
- snprintf(volume_name, sizeof(volume_name),"%s", /* Flawfinder: ignore */
+ snprintf(target_volume, sizeof(target_volume),"%s", /* Flawfinder: ignore */
mCharacter->findCollisionVolume(shared_constraintp->mTargetConstraintVolume)->getName().c_str());
}
- success &= dp.packBinaryDataFixed((U8*)volume_name, 16, "target_volume");
+ success &= dp.packBinaryDataFixed((U8*)target_volume, 16, "target_volume");
success &= dp.packVector3(shared_constraintp->mTargetConstraintOffset, "target_offset");
success &= dp.packVector3(shared_constraintp->mTargetConstraintDir, "target_dir");
success &= dp.packF32(shared_constraintp->mEaseInStartTime, "ease_in_start");
success &= dp.packF32(shared_constraintp->mEaseInStopTime, "ease_in_stop");
success &= dp.packF32(shared_constraintp->mEaseOutStartTime, "ease_out_start");
success &= dp.packF32(shared_constraintp->mEaseOutStopTime, "ease_out_stop");
+
+ LL_DEBUGS("BVH") << " chain_length " << shared_constraintp->mChainLength << LL_ENDL;
+ LL_DEBUGS("BVH") << " constraint_type " << (S32)shared_constraintp->mConstraintType << LL_ENDL;
+ LL_DEBUGS("BVH") << " source_volume " << source_volume << LL_ENDL;
+ LL_DEBUGS("BVH") << " source_offset " << shared_constraintp->mSourceConstraintOffset << LL_ENDL;
+ LL_DEBUGS("BVH") << " target_volume " << target_volume << LL_ENDL;
+ LL_DEBUGS("BVH") << " target_offset " << shared_constraintp->mTargetConstraintOffset << LL_ENDL;
+ LL_DEBUGS("BVH") << " target_dir " << shared_constraintp->mTargetConstraintDir << LL_ENDL;
+ LL_DEBUGS("BVH") << " ease_in_start " << shared_constraintp->mEaseInStartTime << LL_ENDL;
+ LL_DEBUGS("BVH") << " ease_in_stop " << shared_constraintp->mEaseInStopTime << LL_ENDL;
+ LL_DEBUGS("BVH") << " ease_out_start " << shared_constraintp->mEaseOutStartTime << LL_ENDL;
+ LL_DEBUGS("BVH") << " ease_out_stop " << shared_constraintp->mEaseOutStopTime << LL_ENDL;
}
return success;
@@ -2149,7 +1979,7 @@ void LLKeyframeMotion::setEmote(const LLUUID& emote_id)
}
else
{
- mJointMotionList->mEmoteName = "";
+ mJointMotionList->mEmoteName.clear();
}
}
@@ -2220,9 +2050,9 @@ void LLKeyframeMotion::setLoopIn(F32 in_point)
rot_curve->mLoopInKey.mTime = mJointMotionList->mLoopInPoint;
scale_curve->mLoopInKey.mTime = mJointMotionList->mLoopInPoint;
- pos_curve->mLoopInKey.mPosition = pos_curve->getValue(mJointMotionList->mLoopInPoint, mJointMotionList->mDuration);
- rot_curve->mLoopInKey.mRotation = rot_curve->getValue(mJointMotionList->mLoopInPoint, mJointMotionList->mDuration);
- scale_curve->mLoopInKey.mScale = scale_curve->getValue(mJointMotionList->mLoopInPoint, mJointMotionList->mDuration);
+ pos_curve->mLoopInKey.mValue = pos_curve->getValue(mJointMotionList->mLoopInPoint, mJointMotionList->mDuration);
+ rot_curve->mLoopInKey.mValue = rot_curve->getValue(mJointMotionList->mLoopInPoint, mJointMotionList->mDuration);
+ scale_curve->mLoopInKey.mValue = scale_curve->getValue(mJointMotionList->mLoopInPoint, mJointMotionList->mDuration);
}
}
}
@@ -2249,9 +2079,9 @@ void LLKeyframeMotion::setLoopOut(F32 out_point)
rot_curve->mLoopOutKey.mTime = mJointMotionList->mLoopOutPoint;
scale_curve->mLoopOutKey.mTime = mJointMotionList->mLoopOutPoint;
- pos_curve->mLoopOutKey.mPosition = pos_curve->getValue(mJointMotionList->mLoopOutPoint, mJointMotionList->mDuration);
- rot_curve->mLoopOutKey.mRotation = rot_curve->getValue(mJointMotionList->mLoopOutPoint, mJointMotionList->mDuration);
- scale_curve->mLoopOutKey.mScale = scale_curve->getValue(mJointMotionList->mLoopOutPoint, mJointMotionList->mDuration);
+ pos_curve->mLoopOutKey.mValue = pos_curve->getValue(mJointMotionList->mLoopOutPoint, mJointMotionList->mDuration);
+ rot_curve->mLoopOutKey.mValue = rot_curve->getValue(mJointMotionList->mLoopOutPoint, mJointMotionList->mDuration);
+ scale_curve->mLoopOutKey.mValue = scale_curve->getValue(mJointMotionList->mLoopOutPoint, mJointMotionList->mDuration);
}
}
}
@@ -2284,7 +2114,7 @@ void LLKeyframeMotion::onLoadComplete(LLVFS *vfs,
LLCharacter* character = *char_iter;
// look for an existing instance of this motion
- LLKeyframeMotion* motionp = (LLKeyframeMotion*) character->findMotion(asset_uuid);
+ LLKeyframeMotion* motionp = dynamic_cast (character->findMotion(asset_uuid));
if (motionp)
{
if (0 == status)
@@ -2299,11 +2129,11 @@ void LLKeyframeMotion::onLoadComplete(LLVFS *vfs,
U8* buffer = new U8[size];
file.read((U8*)buffer, size); /*Flawfinder: ignore*/
-
- LL_DEBUGS() << "Loading keyframe data for: " << motionp->getName() << ":" << motionp->getID() << " (" << size << " bytes)" << LL_ENDL;
+
+ LL_DEBUGS("Animation") << "Loading keyframe data for: " << motionp->getName() << ":" << motionp->getID() << " (" << size << " bytes)" << LL_ENDL;
LLDataPackerBinaryBuffer dp(buffer, size);
- if (motionp->deserialize(dp))
+ if (motionp->deserialize(dp, asset_uuid))
{
motionp->mAssetStatus = ASSET_LOADED;
}
@@ -2344,9 +2174,9 @@ void LLKeyframeDataCache::dumpDiagInfo(int quiet)
if (quiet < 2)
{
- LL_INFOS() << "-----------------------------------------------------" << LL_ENDL;
- LL_INFOS() << " Global Motion Table" << LL_ENDL;
- LL_INFOS() << "-----------------------------------------------------" << LL_ENDL;
+ LL_INFOS() << "-----------------------------------------------------" << LL_ENDL;
+ LL_INFOS() << " Global Motion Table (DEBUG only)" << LL_ENDL;
+ LL_INFOS() << "-----------------------------------------------------" << LL_ENDL;
}
// print each loaded mesh, and it's memory usage
@@ -2364,8 +2194,8 @@ void LLKeyframeDataCache::dumpDiagInfo(int quiet)
if (motion_list_p)
{
- joint_motion_kb = motion_list_p->dumpDiagInfo(quiet);
- total_size += joint_motion_kb;
+ joint_motion_kb = motion_list_p->dumpDiagInfo(quiet);
+ total_size += joint_motion_kb;
}
}
diff --git a/indra/llcharacter/llkeyframemotion.h b/indra/llcharacter/llkeyframemotion.h
index 4c54d55006..82244465bf 100644
--- a/indra/llcharacter/llkeyframemotion.h
+++ b/indra/llcharacter/llkeyframemotion.h
@@ -171,6 +171,22 @@ int AICachedPointerPtr::sCnt;
//-----------------------------------------------------------------------------
// class LLKeyframeMotion
//-----------------------------------------------------------------------------
+
+namespace LLKeyframeMotionLerp
+{
+ template
+ inline T lerp(F32 t, const T& before, const T& after)
+ {
+ return ::lerp(before, after, t);
+ }
+
+ template<>
+ inline LLQuaternion lerp(F32 t, const LLQuaternion& before, const LLQuaternion& after)
+ {
+ return nlerp(t, before, after);
+ }
+}
+
class LLKeyframeMotion :
public LLMotion
{
@@ -266,7 +282,7 @@ class LLKeyframeMotion :
public:
U32 getFileSize();
BOOL serialize(LLDataPacker& dp) const;
- BOOL deserialize(LLDataPacker& dp);
+ BOOL deserialize(LLDataPacker& dp, const LLUUID& asset_id);
BOOL isLoaded() { return !!mJointMotionList; }
@@ -387,101 +403,84 @@ class LLKeyframeMotion :
enum InterpolationType { IT_STEP, IT_LINEAR, IT_SPLINE };
- //-------------------------------------------------------------------------
- // ScaleKey
- //-------------------------------------------------------------------------
- class ScaleKey
- {
- public:
- ScaleKey() { mTime = 0.0f; }
- ScaleKey(F32 time, const LLVector3 &scale) { mTime = time; mScale = scale; }
-
- F32 mTime;
- LLVector3 mScale;
- };
-
- //-------------------------------------------------------------------------
- // RotationKey
- //-------------------------------------------------------------------------
- class RotationKey
- {
- public:
- RotationKey() { mTime = 0.0f; }
- RotationKey(F32 time, const LLQuaternion &rotation) { mTime = time; mRotation = rotation; }
-
- F32 mTime;
- LLQuaternion mRotation;
- };
-
- //-------------------------------------------------------------------------
- // PositionKey
- //-------------------------------------------------------------------------
- class PositionKey
+ template
+ struct Curve
{
- public:
- PositionKey() { mTime = 0.0f; }
- PositionKey(F32 time, const LLVector3 &position) { mTime = time; mPosition = position; }
-
- F32 mTime;
- LLVector3 mPosition;
- };
-
- //-------------------------------------------------------------------------
- // ScaleCurve
- //-------------------------------------------------------------------------
- class ScaleCurve
- {
- public:
- ScaleCurve();
- ~ScaleCurve();
- LLVector3 getValue(F32 time, F32 duration);
- LLVector3 interp(F32 u, ScaleKey& before, ScaleKey& after);
-
- InterpolationType mInterpolationType;
- S32 mNumKeys;
- typedef std::map key_map_t;
+ struct Key
+ {
+ Key() = default;
+ Key(F32 time, const T& value) { mTime = time; mValue = value; }
+ F32 mTime = 0;
+ T mValue;
+ };
+
+ T interp(F32 u, Key& before, Key& after)
+ {
+ switch (mInterpolationType)
+ {
+ case IT_STEP:
+ return before.mValue;
+ default:
+ case IT_LINEAR:
+ case IT_SPLINE:
+ return LLKeyframeMotionLerp::lerp(u, before.mValue, after.mValue);
+ }
+ }
+
+ T getValue(F32 time, F32 duration)
+ {
+ if (mKeys.empty())
+ {
+ return T();
+ }
+
+ T value;
+ typename key_map_t::iterator right = std::lower_bound(mKeys.begin(), mKeys.end(), time, [](const auto& a, const auto& b) { return a.first < b; });
+ if (right == mKeys.end())
+ {
+ // Past last key
+ --right;
+ value = right->second.mValue;
+ }
+ else if (right == mKeys.begin() || right->first == time)
+ {
+ // Before first key or exactly on a key
+ value = right->second.mValue;
+ }
+ else
+ {
+ // Between two keys
+ typename key_map_t::iterator left = right; --left;
+ F32 index_before = left->first;
+ F32 index_after = right->first;
+ Key& pos_before = left->second;
+ Key& pos_after = right->second;
+ if (right == mKeys.end())
+ {
+ pos_after = mLoopInKey;
+ index_after = duration;
+ }
+
+ F32 u = (time - index_before) / (index_after - index_before);
+ value = interp(u, pos_before, pos_after);
+ }
+ return value;
+ }
+
+ InterpolationType mInterpolationType = LLKeyframeMotion::IT_LINEAR;
+ S32 mNumKeys = 0;
+ typedef std::vector< std::pair > key_map_t;
key_map_t mKeys;
- ScaleKey mLoopInKey;
- ScaleKey mLoopOutKey;
+ Key mLoopInKey;
+ Key mLoopOutKey;
};
- //-------------------------------------------------------------------------
- // RotationCurve
- //-------------------------------------------------------------------------
- class RotationCurve
- {
- public:
- RotationCurve();
- ~RotationCurve();
- LLQuaternion getValue(F32 time, F32 duration);
- LLQuaternion interp(F32 u, RotationKey& before, RotationKey& after);
-
- InterpolationType mInterpolationType;
- S32 mNumKeys;
- typedef std::map key_map_t;
- key_map_t mKeys;
- RotationKey mLoopInKey;
- RotationKey mLoopOutKey;
- };
-
- //-------------------------------------------------------------------------
- // PositionCurve
- //-------------------------------------------------------------------------
- class PositionCurve
- {
- public:
- PositionCurve();
- ~PositionCurve();
- LLVector3 getValue(F32 time, F32 duration);
- LLVector3 interp(F32 u, PositionKey& before, PositionKey& after);
-
- InterpolationType mInterpolationType;
- S32 mNumKeys;
- typedef std::map key_map_t;
- key_map_t mKeys;
- PositionKey mLoopInKey;
- PositionKey mLoopOutKey;
- };
+ typedef Curve ScaleCurve;
+ typedef ScaleCurve::Key ScaleKey;
+ typedef Curve RotationCurve;
+ typedef RotationCurve::Key RotationKey;
+ typedef Curve PositionCurve;
+ typedef PositionCurve::Key PositionKey;
//-------------------------------------------------------------------------
// JointMotion
diff --git a/indra/llcharacter/llkeyframewalkmotion.cpp b/indra/llcharacter/llkeyframewalkmotion.cpp
index 8a6eedaaa2..3ec5b2cba3 100644
--- a/indra/llcharacter/llkeyframewalkmotion.cpp
+++ b/indra/llcharacter/llkeyframewalkmotion.cpp
@@ -140,14 +140,18 @@ BOOL LLKeyframeWalkMotion::onUpdate(F32 time, U8* joint_mask)
//-----------------------------------------------------------------------------
LLWalkAdjustMotion::LLWalkAdjustMotion(LLUUID const& id, LLMotionController* controller) :
AIMaskedMotion(id, controller, ANIM_AGENT_WALK_ADJUST),
+ mCharacter(NULL),
mLastTime(0.f),
mAnimSpeed(0.f),
mAdjustedSpeed(0.f),
mRelativeDir(0.f),
- mAnkleOffset(0.f)
+ mAnkleOffset(0.f),
+ mLeftAnkleJoint(NULL),
+ mRightAnkleJoint(NULL),
+ mPelvisJoint(NULL),
+ mPelvisState(new LLJointState)
{
mName = "walk_adjust";
- mPelvisState = new LLJointState;
}
//-----------------------------------------------------------------------------
@@ -258,7 +262,7 @@ BOOL LLWalkAdjustMotion::onUpdate(F32 time, U8* joint_mask)
// but this will cause the animation playback rate calculation below to
// kick in too slowly and sometimes start playing the animation in reverse.
- //mPelvisOffset -= PELVIS_COMPENSATION_WIEGHT * (foot_slip_vector * world_to_avatar_rot);//lerp(LLVector3::zero, -1.f * (foot_slip_vector * world_to_avatar_rot), LLCriticalDamp::getInterpolant(0.1f));
+ //mPelvisOffset -= PELVIS_COMPENSATION_WIEGHT * (foot_slip_vector * world_to_avatar_rot);//lerp(LLVector3::zero, -1.f * (foot_slip_vector * world_to_avatar_rot), LLSmoothInterpolation::getInterpolant(0.1f));
////F32 drift_comp_max = DRIFT_COMP_MAX_TOTAL * (llclamp(speed, 0.f, DRIFT_COMP_MAX_SPEED) / DRIFT_COMP_MAX_SPEED);
//F32 drift_comp_max = DRIFT_COMP_MAX_TOTAL;
@@ -287,7 +291,7 @@ BOOL LLWalkAdjustMotion::onUpdate(F32 time, U8* joint_mask)
F32 desired_speed_multiplier = llclamp(speed / foot_speed, min_speed_multiplier, ANIM_SPEED_MAX);
// blend towards new speed adjustment value
- F32 new_speed_adjust = lerp(mAdjustedSpeed, desired_speed_multiplier, LLCriticalDamp::getInterpolant(SPEED_ADJUST_TIME_CONSTANT));
+ F32 new_speed_adjust = LLSmoothInterpolation::lerp(mAdjustedSpeed, desired_speed_multiplier, SPEED_ADJUST_TIME_CONSTANT);
// limit that rate at which the speed adjustment changes
F32 speedDelta = llclamp(new_speed_adjust - mAdjustedSpeed, -SPEED_ADJUST_MAX_SEC * delta_time, SPEED_ADJUST_MAX_SEC * delta_time);
@@ -305,8 +309,8 @@ BOOL LLWalkAdjustMotion::onUpdate(F32 time, U8* joint_mask)
{ // standing/turning
// damp out speed adjustment to 0
- mAnimSpeed = lerp(mAnimSpeed, 1.f, LLCriticalDamp::getInterpolant(0.2f));
- //mPelvisOffset = lerp(mPelvisOffset, LLVector3::zero, LLCriticalDamp::getInterpolant(0.2f));
+ mAnimSpeed = LLSmoothInterpolation::lerp(mAnimSpeed, 1.f, 0.2f);
+ //mPelvisOffset = lerp(mPelvisOffset, LLVector3::zero, LLSmoothInterpolation::getInterpolant(0.2f));
}
// broadcast walk speed change
@@ -333,6 +337,7 @@ void LLWalkAdjustMotion::onDeactivate()
//-----------------------------------------------------------------------------
LLFlyAdjustMotion::LLFlyAdjustMotion(LLUUID const& id, LLMotionController* controller)
: AIMaskedMotion(id, controller, ANIM_AGENT_FLY_ADJUST),
+ mCharacter(NULL),
mRoll(0.f)
{
mName = "fly_adjust";
@@ -384,7 +389,7 @@ BOOL LLFlyAdjustMotion::onUpdate(F32 time, U8* joint_mask)
F32 target_roll = llclamp(ang_vel.mV[VZ], -4.f, 4.f) * roll_factor;
// roll is critically damped interpolation between current roll and angular velocity-derived target roll
- mRoll = lerp(mRoll, target_roll, LLCriticalDamp::getInterpolant(0.1f));
+ mRoll = LLSmoothInterpolation::lerp(mRoll, target_roll, U32Milliseconds(100));
LLQuaternion roll(mRoll, LLVector3(0.f, 0.f, 1.f));
mPelvisState->setRotation(roll);
diff --git a/indra/llcharacter/llmotion.cpp b/indra/llcharacter/llmotion.cpp
index 526341d20f..6a70c76b9a 100644
--- a/indra/llcharacter/llmotion.cpp
+++ b/indra/llcharacter/llmotion.cpp
@@ -180,8 +180,8 @@ LLMotion::LLMotion(LLUUID const& id, LLMotionController* controller) :
mDeactivateCallback(NULL),
mDeactivateCallbackUserData(NULL)
{
- for (int i=0; i<3; ++i)
- memset(&mJointSignature[i][0], 0, sizeof(U8) * LL_CHARACTER_MAX_JOINTS);
+ for (S32 i=0; i<3; ++i)
+ memset(&mJointSignature[i][0], 0, sizeof(U8) * LL_CHARACTER_MAX_ANIMATED_JOINTS);
}
//-----------------------------------------------------------------------------
@@ -199,7 +199,7 @@ void LLMotion::fadeOut()
{
if (mFadeWeight > 0.01f)
{
- mFadeWeight = lerp(mFadeWeight, 0.f, LLCriticalDamp::getInterpolant(0.15f));
+ mFadeWeight = lerp(mFadeWeight, 0.f, LLSmoothInterpolation::getInterpolant(0.15f));
}
else
{
@@ -214,7 +214,7 @@ void LLMotion::fadeIn()
{
if (mFadeWeight < 0.99f)
{
- mFadeWeight = lerp(mFadeWeight, 1.f, LLCriticalDamp::getInterpolant(0.15f));
+ mFadeWeight = lerp(mFadeWeight, 1.f, LLSmoothInterpolation::getInterpolant(0.15f));
}
else
{
@@ -237,9 +237,15 @@ void LLMotion::addJointState(const LLPointer& jointState)
U32 usage = jointState->getUsage();
// for now, usage is everything
- mJointSignature[0][jointState->getJoint()->getJointNum()] = (usage & LLJointState::POS) ? (0xff >> (7 - priority)) : 0;
- mJointSignature[1][jointState->getJoint()->getJointNum()] = (usage & LLJointState::ROT) ? (0xff >> (7 - priority)) : 0;
- mJointSignature[2][jointState->getJoint()->getJointNum()] = (usage & LLJointState::SCALE) ? (0xff >> (7 - priority)) : 0;
+ S32 joint_num = jointState->getJoint()->getJointNum();
+ if ((joint_num >= (S32)LL_CHARACTER_MAX_ANIMATED_JOINTS) || (joint_num < 0))
+ {
+ LL_WARNS() << "joint_num " << joint_num << " is outside of legal range [0-" << LL_CHARACTER_MAX_ANIMATED_JOINTS << ") for joint " << jointState->getJoint()->getName() << LL_ENDL;
+ return;
+ }
+ mJointSignature[0][joint_num] = (usage & LLJointState::POS) ? (0xff >> (7 - priority)) : 0;
+ mJointSignature[1][joint_num] = (usage & LLJointState::ROT) ? (0xff >> (7 - priority)) : 0;
+ mJointSignature[2][joint_num] = (usage & LLJointState::SCALE) ? (0xff >> (7 - priority)) : 0;
}
void LLMotion::setDeactivateCallback( void (*cb)(void *), void* userdata )
diff --git a/indra/llcharacter/llmotion.h b/indra/llcharacter/llmotion.h
index 8fe6010abf..6448310b2c 100644
--- a/indra/llcharacter/llmotion.h
+++ b/indra/llcharacter/llmotion.h
@@ -274,7 +274,7 @@ class LLMotion : public AISyncClientMotion
F32 mSendStopTimestamp; // time when simulator should be told to stop this motion
F32 mResidualWeight; // blend weight at beginning of stop motion phase
F32 mFadeWeight; // for fading in and out based on LOD
- U8 mJointSignature[3][LL_CHARACTER_MAX_JOINTS]; // signature of which joints are animated at what priority
+ U8 mJointSignature[3][LL_CHARACTER_MAX_ANIMATED_JOINTS]; // signature of which joints are animated at what priority
void (*mDeactivateCallback)(void* data);
void* mDeactivateCallbackUserData;
};
diff --git a/indra/llcharacter/llmotioncontroller.cpp b/indra/llcharacter/llmotioncontroller.cpp
index 6d1ae77613..3f5b65f527 100644
--- a/indra/llcharacter/llmotioncontroller.cpp
+++ b/indra/llcharacter/llmotioncontroller.cpp
@@ -42,7 +42,7 @@
#include "llanimationstates.h"
#include "llstl.h"
-const S32 NUM_JOINT_SIGNATURE_STRIDES = LL_CHARACTER_MAX_JOINTS / 4;
+const S32 NUM_JOINT_SIGNATURE_STRIDES = LL_CHARACTER_MAX_ANIMATED_JOINTS / 4;
const U32 MAX_MOTION_INSTANCES = 32;
//-----------------------------------------------------------------------------
@@ -83,7 +83,7 @@ LLMotionRegistry::~LLMotionRegistry()
BOOL LLMotionRegistry::registerMotion( const LLUUID& id, LLMotionConstructor constructor )
{
// LL_INFOS() << "Registering motion: " << name << LL_ENDL;
- return mMotionTable.insert(std::make_pair(id,constructor)).second;
+ return mMotionTable.emplace(id, constructor).second;
}
//-----------------------------------------------------------------------------
@@ -126,22 +126,22 @@ LLMotion* LLMotionRegistry::createMotion(LLUUID const& id, LLMotionController* c
// Class Constructor
//-----------------------------------------------------------------------------
LLMotionController::LLMotionController()
- : mIsSelf(FALSE),
- mTimeFactor(sCurrentTimeFactor),
+ : mTimeFactor(sCurrentTimeFactor),
mCharacter(NULL),
+ mAnimTime(0.f),
mActiveMask(0),
mDisableSyncing(0),
mHidden(false),
mHaveVisibleSyncedMotions(false),
mPrevTimerElapsed(0.f),
- mAnimTime(0.f),
mLastTime(0.0f),
mHasRunOnce(FALSE),
mPaused(FALSE),
- mPauseTime(0.f),
+ mPausedFrame(0),
mTimeStep(0.f),
mTimeStepCount(0),
- mLastInterp(0.f)
+ mLastInterp(0.f),
+ mIsSelf(FALSE)
{
}
@@ -200,7 +200,7 @@ void LLMotionController::purgeExcessMotions()
}
//
- std::set motions_to_kill;
+ uuid_set_t motions_to_kill;
if (1) // Singu: leave indentation alone...
{
@@ -220,7 +220,7 @@ void LLMotionController::purgeExcessMotions()
}
// clean up all inactive, loaded motions
- for (std::set::iterator motion_it = motions_to_kill.begin();
+ for (auto motion_it = motions_to_kill.begin();
motion_it != motions_to_kill.end();
++motion_it)
{
@@ -467,7 +467,7 @@ BOOL LLMotionController::stopMotionLocally(const LLUUID &id, BOOL stop_immediate
{
// if already inactive, return false
LLMotion *motion = findMotion(id);
- return stopMotionInstance(motion, stop_immediate);
+ return stopMotionInstance(motion, stop_immediate||mPaused);
}
BOOL LLMotionController::stopMotionInstance(LLMotion* motion, BOOL stop_immediate)
@@ -517,8 +517,8 @@ void LLMotionController::updateAdditiveMotions()
//-----------------------------------------------------------------------------
void LLMotionController::resetJointSignatures()
{
- memset(&mJointSignature[0][0], 0, sizeof(U8) * LL_CHARACTER_MAX_JOINTS);
- memset(&mJointSignature[1][0], 0, sizeof(U8) * LL_CHARACTER_MAX_JOINTS);
+ memset(&mJointSignature[0][0], 0, sizeof(U8) * LL_CHARACTER_MAX_ANIMATED_JOINTS);
+ memset(&mJointSignature[1][0], 0, sizeof(U8) * LL_CHARACTER_MAX_ANIMATED_JOINTS);
}
//-----------------------------------------------------------------------------
@@ -577,14 +577,12 @@ void LLMotionController::updateIdleActiveMotions()
//-----------------------------------------------------------------------------
// updateMotionsByType()
//-----------------------------------------------------------------------------
-static LLFastTimer::DeclareTimer FTM_MOTION_ON_UPDATE("Motion onUpdate");
+static LLTrace::BlockTimerStatHandle FTM_MOTION_ON_UPDATE("Motion onUpdate");
void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_type)
{
BOOL update_result = TRUE;
- U8 last_joint_signature[LL_CHARACTER_MAX_JOINTS];
-
- memset(&last_joint_signature, 0, sizeof(U8) * LL_CHARACTER_MAX_JOINTS);
+ U8 last_joint_signature[LL_CHARACTER_MAX_ANIMATED_JOINTS] = {0};
// iterate through active motions in chronological order
for (motion_list_t::iterator iter = mActiveMotions.begin();
@@ -737,7 +735,7 @@ void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_ty
// perform motion update
{
- LLFastTimer t(FTM_MOTION_ON_UPDATE);
+ LL_RECORD_BLOCK_TIME(FTM_MOTION_ON_UPDATE);
update_result = motionp->onUpdate(mAnimTime - motionp->mActivationTimestamp, last_joint_signature);
}
}
@@ -881,7 +879,7 @@ void LLMotionController::updateMotions(bool force_update)
// Moreover, just rounding off to the nearest integer with ll_round(update_time / mTimeStep) makes a lot more sense:
// it is the best we can do to get as close to what we should draw as possible.
// However, mAnimTime may only be incremented; therefore make sure of that with the llmax.
- S32 quantum_count = llmax(ll_round(update_time / mTimeStep), llceil(mAnimTime / mTimeStep));
+ S32 quantum_count = llmax(ll_pos_round(update_time / mTimeStep), llceil(mAnimTime / mTimeStep));
//
if (quantum_count == mTimeStepCount)
{
@@ -1314,6 +1312,7 @@ void LLMotionController::pauseAllMotions()
{
//LL_INFOS() << "Pausing animations..." << LL_ENDL;
mPaused = TRUE;
+ mPausedFrame = LLFrameTimer::getFrameCount();
}
}
diff --git a/indra/llcharacter/llmotioncontroller.h b/indra/llcharacter/llmotioncontroller.h
index 054f1c2f98..843cac4252 100644
--- a/indra/llcharacter/llmotioncontroller.h
+++ b/indra/llcharacter/llmotioncontroller.h
@@ -162,16 +162,20 @@ class LLMotionController
void pauseAllMotions();
void unpauseAllMotions();
BOOL isPaused() const { return mPaused; }
+ U64 getPausedFrame() const { return mPausedFrame; }
//
void requestPause(std::vector& avatar_pause_handles);
void pauseAllSyncedCharacters(std::vector& avatar_pause_handles);
//
void setTimeStep(F32 step);
+ F32 getTimeStep() const { return mTimeStep; }
void setTimeFactor(F32 time_factor);
F32 getTimeFactor() const { return mTimeFactor; }
+ F32 getAnimTime() const { return mAnimTime; }
+
motion_list_t& getActiveMotions() { return mActiveMotions; }
void incMotionCounts(S32& num_motions, S32& num_loading_motions, S32& num_loaded_motions, S32& num_active_motions, S32& num_deprecated_motions);
@@ -248,12 +252,12 @@ class LLMotionController
F32 mLastTime;
BOOL mHasRunOnce;
BOOL mPaused;
- F32 mPauseTime;
+ U64 mPausedFrame;
F32 mTimeStep;
S32 mTimeStepCount;
F32 mLastInterp;
- U8 mJointSignature[2][LL_CHARACTER_MAX_JOINTS];
+ U8 mJointSignature[2][LL_CHARACTER_MAX_ANIMATED_JOINTS];
//
public:
@@ -263,7 +267,6 @@ class LLMotionController
bool syncing_disabled(void) const { return mDisableSyncing >= 100; }
// Accessors needed for synchronization.
- F32 getAnimTime(void) const { return mAnimTime; }
bool isHidden(void) const { return mHidden; }
// Called often. Should return false if we still need to keep updating our motions even if we're not visible.
diff --git a/indra/llcharacter/llmultigesture.cpp b/indra/llcharacter/llmultigesture.cpp
index a689e840a2..64de502b60 100644
--- a/indra/llcharacter/llmultigesture.cpp
+++ b/indra/llcharacter/llmultigesture.cpp
@@ -36,7 +36,7 @@
#include "lldatapacker.h"
#include "llstl.h"
-const S32 GESTURE_VERSION = 2;
+constexpr S32 GESTURE_VERSION = 2;
//---------------------------------------------------------------------------
// LLMultiGesture
@@ -48,10 +48,10 @@ LLMultiGesture::LLMultiGesture()
mTrigger(),
mReplaceText(),
mSteps(),
- mPlaying(FALSE),
+ mPlaying(false),
mLocal(false),
mCurrentStep(0),
- mDoneCallback(NULL)
+ mDoneCallback(nullptr)
{
reset();
}
@@ -63,13 +63,13 @@ LLMultiGesture::~LLMultiGesture()
void LLMultiGesture::reset()
{
- mPlaying = FALSE;
+ mPlaying = false;
mLocal = false;
mCurrentStep = 0;
mWaitTimer.reset();
- mWaitingTimer = FALSE;
- mWaitingAnimations = FALSE;
- mWaitingAtEnd = FALSE;
+ mWaitingTimer = false;
+ mWaitingAnimations = false;
+ mWaitingAtEnd = false;
mRequestedAnimIDs.clear();
mPlayingAnimIDs.clear();
}
@@ -88,10 +88,8 @@ S32 LLMultiGesture::getMaxSerialSize() const
max_size += 64; // step count S32
- std::vector::const_iterator it;
- for (it = mSteps.begin(); it != mSteps.end(); ++it)
+ for (const auto& step : mSteps)
{
- LLGestureStep* step = *it;
max_size += 64; // type S32
max_size += step->getMaxSerialSize();
}
@@ -104,10 +102,8 @@ S32 LLMultiGesture::getMaxSerialSize() const
max_size += sizeof(S32); // step count
- std::vector::const_iterator it;
- for (it = mSteps.begin(); it != mSteps.end(); ++it)
+ for (const auto& step : mSteps)
{
- LLGestureStep* step = *it;
max_size += sizeof(S32); // type
max_size += step->getMaxSerialSize();
}
@@ -116,7 +112,7 @@ S32 LLMultiGesture::getMaxSerialSize() const
return max_size;
}
-BOOL LLMultiGesture::serialize(LLDataPacker& dp) const
+bool LLMultiGesture::serialize(LLDataPacker& dp) const
{
dp.packS32(GESTURE_VERSION, "version");
dp.packU8(mKey, "key");
@@ -126,22 +122,18 @@ BOOL LLMultiGesture::serialize(LLDataPacker& dp) const
S32 count = (S32)mSteps.size();
dp.packS32(count, "step_count");
- S32 i;
- for (i = 0; i < count; ++i)
+ for (const auto& step : mSteps)
{
- LLGestureStep* step = mSteps[i];
-
dp.packS32(step->getType(), "step_type");
- BOOL ok = step->serialize(dp);
- if (!ok)
+ if (!step->serialize(dp))
{
- return FALSE;
+ return false;
}
}
- return TRUE;
+ return true;
}
-BOOL LLMultiGesture::deserialize(LLDataPacker& dp)
+bool LLMultiGesture::deserialize(LLDataPacker& dp)
{
S32 version;
dp.unpackS32(version, "version");
@@ -150,15 +142,12 @@ BOOL LLMultiGesture::deserialize(LLDataPacker& dp)
LL_WARNS() << "Bad LLMultiGesture version " << version
<< " should be " << GESTURE_VERSION
<< LL_ENDL;
- return FALSE;
+ return false;
}
dp.unpackU8(mKey, "key");
dp.unpackU32(mMask, "mask");
-
-
dp.unpackString(mTrigger, "trigger");
-
dp.unpackString(mReplaceText, "replace");
S32 count;
@@ -166,58 +155,31 @@ BOOL LLMultiGesture::deserialize(LLDataPacker& dp)
if (count < 0)
{
LL_WARNS() << "Bad LLMultiGesture step count " << count << LL_ENDL;
- return FALSE;
+ return false;
}
- S32 i;
- for (i = 0; i < count; ++i)
+ std::unique_ptr step;
+ for (S32 i = 0; i < count; ++i)
{
S32 type;
dp.unpackS32(type, "step_type");
- EStepType step_type = (EStepType)type;
- switch(step_type)
+ switch((EStepType)type)
{
- case STEP_ANIMATION:
- {
- LLGestureStepAnimation* step = new LLGestureStepAnimation();
- BOOL ok = step->deserialize(dp);
- if (!ok) return FALSE;
- mSteps.push_back(step);
- break;
- }
- case STEP_SOUND:
- {
- LLGestureStepSound* step = new LLGestureStepSound();
- BOOL ok = step->deserialize(dp);
- if (!ok) return FALSE;
- mSteps.push_back(step);
- break;
- }
- case STEP_CHAT:
- {
- LLGestureStepChat* step = new LLGestureStepChat();
- BOOL ok = step->deserialize(dp);
- if (!ok) return FALSE;
- mSteps.push_back(step);
- break;
- }
- case STEP_WAIT:
- {
- LLGestureStepWait* step = new LLGestureStepWait();
- BOOL ok = step->deserialize(dp);
- if (!ok) return FALSE;
- mSteps.push_back(step);
- break;
- }
+ case STEP_ANIMATION: step.reset(new LLGestureStepAnimation); break;
+ case STEP_SOUND: step.reset(new LLGestureStepSound); break;
+ case STEP_CHAT: step.reset(new LLGestureStepChat); break;
+ case STEP_WAIT: step.reset(new LLGestureStepWait); break;
default:
{
LL_WARNS() << "Bad LLMultiGesture step type " << type << LL_ENDL;
- return FALSE;
+ return false;
}
}
+ if (!step->deserialize(dp)) return false;
+ mSteps.push_back(step.release());
}
- return TRUE;
+ return true;
}
void LLMultiGesture::dump()
@@ -226,10 +188,8 @@ void LLMultiGesture::dump()
<< " trigger " << mTrigger
<< " replace " << mReplaceText
<< LL_ENDL;
- U32 i;
- for (i = 0; i < mSteps.size(); ++i)
+ for (const auto& step : mSteps)
{
- LLGestureStep* step = mSteps[i];
step->dump();
}
}
@@ -264,21 +224,21 @@ S32 LLGestureStepAnimation::getMaxSerialSize() const
return max_size;
}
-BOOL LLGestureStepAnimation::serialize(LLDataPacker& dp) const
+bool LLGestureStepAnimation::serialize(LLDataPacker& dp) const
{
dp.packString(mAnimName, "anim_name");
dp.packUUID(mAnimAssetID, "asset_id");
dp.packU32(mFlags, "flags");
- return TRUE;
+ return true;
}
-BOOL LLGestureStepAnimation::deserialize(LLDataPacker& dp)
+bool LLGestureStepAnimation::deserialize(LLDataPacker& dp)
{
dp.unpackString(mAnimName, "anim_name");
// Apparently an earlier version of the gesture code added \r to the end
// of the animation names. Get rid of it. JC
- if (!mAnimName.empty() && mAnimName[mAnimName.length() - 1] == '\r')
+ if (!mAnimName.empty() && mAnimName.back() == '\r')
{
// chop the last character
mAnimName.resize(mAnimName.length() - 1);
@@ -286,29 +246,18 @@ BOOL LLGestureStepAnimation::deserialize(LLDataPacker& dp)
dp.unpackUUID(mAnimAssetID, "asset_id");
dp.unpackU32(mFlags, "flags");
- return TRUE;
+ return true;
}
// *NOTE: result is translated in LLPreviewGesture::getLabel()
std::vector LLGestureStepAnimation::getLabel() const
{
- std::vector strings;
-
-// std::string label;
+/* std::string label;
if (mFlags & ANIM_FLAG_STOP)
- {
- strings.push_back( "AnimFlagStop");
-
-// label = "Stop Animation: ";
- }
+ label = "Stop Animation: ";
else
- {
- strings.push_back( "AnimFlagStart");
-
-// label = "Start Animation: ";
- }
- strings.push_back( mAnimName);
-// label += mAnimName;
- return strings;
+ label = "Start Animation: ";
+ label += mAnimName;*/
+ return {mFlags & ANIM_FLAG_STOP ? "AnimFlagStop" : "AnimFlagStart", mAnimName};
}
void LLGestureStepAnimation::dump()
@@ -346,31 +295,28 @@ S32 LLGestureStepSound::getMaxSerialSize() const
return max_size;
}
-BOOL LLGestureStepSound::serialize(LLDataPacker& dp) const
+bool LLGestureStepSound::serialize(LLDataPacker& dp) const
{
dp.packString(mSoundName, "sound_name");
dp.packUUID(mSoundAssetID, "asset_id");
dp.packU32(mFlags, "flags");
- return TRUE;
+ return true;
}
-BOOL LLGestureStepSound::deserialize(LLDataPacker& dp)
+bool LLGestureStepSound::deserialize(LLDataPacker& dp)
{
dp.unpackString(mSoundName, "sound_name");
dp.unpackUUID(mSoundAssetID, "asset_id");
dp.unpackU32(mFlags, "flags");
- return TRUE;
+ return true;
}
// *NOTE: result is translated in LLPreviewGesture::getLabel()
std::vector LLGestureStepSound::getLabel() const
{
- std::vector strings;
- strings.push_back( "Sound");
- strings.push_back( mSoundName);
// std::string label("Sound: ");
// label += mSoundName;
- return strings;
+ return {"Sound", mSoundName};
}
void LLGestureStepSound::dump()
@@ -406,27 +352,23 @@ S32 LLGestureStepChat::getMaxSerialSize() const
return max_size;
}
-BOOL LLGestureStepChat::serialize(LLDataPacker& dp) const
+bool LLGestureStepChat::serialize(LLDataPacker& dp) const
{
dp.packString(mChatText, "chat_text");
dp.packU32(mFlags, "flags");
- return TRUE;
+ return true;
}
-BOOL LLGestureStepChat::deserialize(LLDataPacker& dp)
+bool LLGestureStepChat::deserialize(LLDataPacker& dp)
{
dp.unpackString(mChatText, "chat_text");
-
dp.unpackU32(mFlags, "flags");
- return TRUE;
+ return true;
}
// *NOTE: result is translated in LLPreviewGesture::getLabel()
std::vector LLGestureStepChat::getLabel() const
{
- std::vector strings;
- strings.push_back("Chat");
- strings.push_back(mChatText);
- return strings;
+ return {"Chat", mChatText};
}
void LLGestureStepChat::dump()
@@ -461,44 +403,26 @@ S32 LLGestureStepWait::getMaxSerialSize() const
return max_size;
}
-BOOL LLGestureStepWait::serialize(LLDataPacker& dp) const
+bool LLGestureStepWait::serialize(LLDataPacker& dp) const
{
dp.packF32(mWaitSeconds, "wait_seconds");
dp.packU32(mFlags, "flags");
- return TRUE;
+ return true;
}
-BOOL LLGestureStepWait::deserialize(LLDataPacker& dp)
+bool LLGestureStepWait::deserialize(LLDataPacker& dp)
{
dp.unpackF32(mWaitSeconds, "wait_seconds");
dp.unpackU32(mFlags, "flags");
- return TRUE;
+ return true;
}
// *NOTE: result is translated in LLPreviewGesture::getLabel()
std::vector LLGestureStepWait::getLabel() const
{
- std::vector strings;
- strings.push_back( "Wait" );
-
-// std::string label("--- Wait: ");
- if (mFlags & WAIT_FLAG_TIME)
- {
- char buffer[64]; /* Flawfinder: ignore */
- snprintf(buffer, sizeof(buffer), "%.1f seconds", (double)mWaitSeconds); /* Flawfinder: ignore */
- strings.push_back(buffer);
-// label += buffer;
- }
- else if (mFlags & WAIT_FLAG_ALL_ANIM)
- {
- strings.push_back("until animations are done");
- // label += "until animations are done";
- }
- else
- {
- strings.push_back("");
- }
-
- return strings;
+ return {"Wait",
+ mFlags & WAIT_FLAG_TIME ? llformat("%.1f seconds", mWaitSeconds)
+ : mFlags & WAIT_FLAG_ALL_ANIM ? "until animations are done"
+ : LLStringUtil::null};
}
diff --git a/indra/llcharacter/llmultigesture.h b/indra/llcharacter/llmultigesture.h
index 8e48213578..68395465bf 100644
--- a/indra/llcharacter/llmultigesture.h
+++ b/indra/llcharacter/llmultigesture.h
@@ -27,7 +27,7 @@
#ifndef LL_LLMULTIGESTURE_H
#define LL_LLMULTIGESTURE_H
-#include
+#include
#include
#include
@@ -46,8 +46,8 @@ class LLMultiGesture
// Maximum number of bytes this could hold once serialized.
S32 getMaxSerialSize() const;
- BOOL serialize(LLDataPacker& dp) const;
- BOOL deserialize(LLDataPacker& dp);
+ bool serialize(LLDataPacker& dp) const;
+ bool deserialize(LLDataPacker& dp);
void dump();
@@ -77,7 +77,7 @@ class LLMultiGesture
std::vector mSteps;
// Is the gesture currently playing?
- BOOL mPlaying;
+ bool mPlaying;
// Is the gesture to be played locally?
bool mLocal;
@@ -86,25 +86,25 @@ class LLMultiGesture
S32 mCurrentStep;
// We're waiting for triggered animations to stop playing
- BOOL mWaitingAnimations;
+ bool mWaitingAnimations;
// We're waiting a fixed amount of time
- BOOL mWaitingTimer;
+ bool mWaitingTimer;
// Waiting after the last step played for all animations to complete
- BOOL mWaitingAtEnd;
+ bool mWaitingAtEnd;
// Timer for waiting
LLFrameTimer mWaitTimer;
- boost::function mDoneCallback;
+ std::function mDoneCallback;
// Animations that we requested to start
- std::set mRequestedAnimIDs;
+ uuid_set_t mRequestedAnimIDs;
// Once the animation starts playing (sim says to start playing)
// the ID is moved from mRequestedAnimIDs to here.
- std::set mPlayingAnimIDs;
+ uuid_set_t mPlayingAnimIDs;
};
@@ -127,14 +127,14 @@ class LLGestureStep
LLGestureStep() {}
virtual ~LLGestureStep() {}
- virtual EStepType getType() = 0;
+ virtual EStepType getType() const = 0;
// Return a user-readable label for this step
virtual std::vector getLabel() const = 0;
virtual S32 getMaxSerialSize() const = 0;
- virtual BOOL serialize(LLDataPacker& dp) const = 0;
- virtual BOOL deserialize(LLDataPacker& dp) = 0;
+ virtual bool serialize(LLDataPacker& dp) const = 0;
+ virtual bool deserialize(LLDataPacker& dp) = 0;
virtual void dump() = 0;
};
@@ -142,7 +142,7 @@ class LLGestureStep
// By default, animation steps start animations.
// If the least significant bit is 1, it will stop animations.
-const U32 ANIM_FLAG_STOP = 0x01;
+constexpr U32 ANIM_FLAG_STOP = 0x01;
class LLGestureStepAnimation : public LLGestureStep
{
@@ -150,15 +150,15 @@ class LLGestureStepAnimation : public LLGestureStep
LLGestureStepAnimation();
virtual ~LLGestureStepAnimation();
- virtual EStepType getType() { return STEP_ANIMATION; }
+ EStepType getType() const override { return STEP_ANIMATION; }
- virtual std::vector getLabel() const;
+ std::vector getLabel() const override;
- virtual S32 getMaxSerialSize() const;
- virtual BOOL serialize(LLDataPacker& dp) const;
- virtual BOOL deserialize(LLDataPacker& dp);
+ S32 getMaxSerialSize() const override;
+ bool serialize(LLDataPacker& dp) const override;
+ bool deserialize(LLDataPacker& dp) override;
- virtual void dump();
+ void dump() override;
public:
std::string mAnimName;
@@ -173,15 +173,15 @@ class LLGestureStepSound : public LLGestureStep
LLGestureStepSound();
virtual ~LLGestureStepSound();
- virtual EStepType getType() { return STEP_SOUND; }
+ EStepType getType() const override { return STEP_SOUND; }
- virtual std::vector getLabel() const;
+ std::vector getLabel() const override;
- virtual S32 getMaxSerialSize() const;
- virtual BOOL serialize(LLDataPacker& dp) const;
- virtual BOOL deserialize(LLDataPacker& dp);
+ S32 getMaxSerialSize() const override;
+ bool serialize(LLDataPacker& dp) const override;
+ bool deserialize(LLDataPacker& dp) override;
- virtual void dump();
+ void dump() override;
public:
std::string mSoundName;
@@ -196,15 +196,15 @@ class LLGestureStepChat : public LLGestureStep
LLGestureStepChat();
virtual ~LLGestureStepChat();
- virtual EStepType getType() { return STEP_CHAT; }
+ EStepType getType() const override { return STEP_CHAT; }
- virtual std::vector getLabel() const;
+ std::vector getLabel() const override;
- virtual S32 getMaxSerialSize() const;
- virtual BOOL serialize(LLDataPacker& dp) const;
- virtual BOOL deserialize(LLDataPacker& dp);
+ S32 getMaxSerialSize() const override;
+ bool serialize(LLDataPacker& dp) const override;
+ bool deserialize(LLDataPacker& dp) override;
- virtual void dump();
+ void dump() override;
public:
std::string mChatText;
@@ -212,8 +212,8 @@ class LLGestureStepChat : public LLGestureStep
};
-const U32 WAIT_FLAG_TIME = 0x01;
-const U32 WAIT_FLAG_ALL_ANIM = 0x02;
+constexpr U32 WAIT_FLAG_TIME = 0x01;
+constexpr U32 WAIT_FLAG_ALL_ANIM = 0x02;
class LLGestureStepWait : public LLGestureStep
{
@@ -221,15 +221,15 @@ class LLGestureStepWait : public LLGestureStep
LLGestureStepWait();
virtual ~LLGestureStepWait();
- virtual EStepType getType() { return STEP_WAIT; }
+ EStepType getType() const override { return STEP_WAIT; }
- virtual std::vector getLabel() const;
+ std::vector getLabel() const override;
- virtual S32 getMaxSerialSize() const;
- virtual BOOL serialize(LLDataPacker& dp) const;
- virtual BOOL deserialize(LLDataPacker& dp);
+ S32 getMaxSerialSize() const override;
+ bool serialize(LLDataPacker& dp) const override;
+ bool deserialize(LLDataPacker& dp) override;
- virtual void dump();
+ void dump() override;
public:
F32 mWaitSeconds;
diff --git a/indra/llcharacter/lltargetingmotion.cpp b/indra/llcharacter/lltargetingmotion.cpp
index 7396a1ff53..9dd581f308 100644
--- a/indra/llcharacter/lltargetingmotion.cpp
+++ b/indra/llcharacter/lltargetingmotion.cpp
@@ -104,7 +104,7 @@ LLMotion::LLMotionInitStatus LLTargetingMotion::onInitialize(LLCharacter *charac
//-----------------------------------------------------------------------------
BOOL LLTargetingMotion::onUpdate(F32 time, U8* joint_mask)
{
- F32 slerp_amt = LLCriticalDamp::getInterpolant(TORSO_TARGET_HALF_LIFE);
+ F32 slerp_amt = LLSmoothInterpolation::getInterpolant(TORSO_TARGET_HALF_LIFE);
LLVector3 target;
LLVector3* lookAtPoint = (LLVector3*)mCharacter->getAnimationData("LookAtPoint");
diff --git a/indra/llcharacter/llvisualparam.h b/indra/llcharacter/llvisualparam.h
index ba6a3d6678..7a6f6a0a1d 100644
--- a/indra/llcharacter/llvisualparam.h
+++ b/indra/llcharacter/llvisualparam.h
@@ -30,10 +30,6 @@
#include "v3math.h"
#include "llstring.h"
#include "llxmltree.h"
-#ifndef BOOST_FUNCTION_HPP_INCLUDED
-#include
-#define BOOST_FUNCTION_HPP_INCLUDED
-#endif
class LLPolyMesh;
class LLXmlTreeNode;
@@ -107,11 +103,23 @@ LL_ALIGN_PREFIX(16)
class LLVisualParam
{
public:
- typedef boost::function visual_param_mapper;
+ typedef std::function visual_param_mapper;
LLVisualParam();
virtual ~LLVisualParam();
+ //
+ void* operator new(size_t size)
+ {
+ return ll_aligned_malloc_16(size);
+ }
+
+ void operator delete(void* ptr)
+ {
+ ll_aligned_free_16(ptr);
+ }
+ //
+
// Special: These functions are overridden by child classes
// (They can not be virtual because they use specific derived Info classes)
LLVisualParamInfo* getInfo() const { return mInfo; }
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 72e03e7092..ea99d74296 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -4,21 +4,29 @@ project(llcommon)
include(Cwdebug)
include(00-Common)
+include(Linking)
include(LLCommon)
+include(EXPAT)
include(APR)
include(Linking)
-include(GoogleBreakpad)
+include(Boost)
+include(OpenSSL)
+include(LLSharedLibs)
+include(Copy3rdPartyLibs)
+include(ZLIB)
+include(URIPARSER)
include_directories(
${EXPAT_INCLUDE_DIRS}
${LLCOMMON_INCLUDE_DIRS}
+ ${OPENSSL_INCLUDE_DIRS}
+ ${JSON_INCLUDE_DIR}
${ZLIB_INCLUDE_DIRS}
${BREAKPAD_INCLUDE_DIRECTORIES}
)
set(llcommon_SOURCE_FILES
aialert.cpp
- aifile.cpp
aiframetimer.cpp
aisyncclient.cpp
aithreadid.cpp
@@ -32,6 +40,7 @@ set(llcommon_SOURCE_FILES
llassettype.cpp
llbase32.cpp
llbase64.cpp
+ llcallbacklist.cpp
llcommon.cpp
llcommonutils.cpp
llcoros.cpp
@@ -78,6 +87,7 @@ set(llcommon_SOURCE_FILES
llrun.cpp
llscopedvolatileaprpool.h
llsd.cpp
+ llsdjson.cpp
llsdparam.cpp
llsdserialize.cpp
llsdserialize_xml.cpp
@@ -94,6 +104,7 @@ set(llcommon_SOURCE_FILES
llthreadsafequeue.cpp
lltimer.cpp
lluri.cpp
+ lluriparser.cpp
lluuid.cpp
llworkerthread.cpp
metaclass.cpp
@@ -107,7 +118,6 @@ set(llcommon_HEADER_FILES
CMakeLists.txt
aialert.h
- aifile.h
aiframetimer.h
airecursive.h
aisyncclient.h
@@ -134,6 +144,7 @@ set(llcommon_HEADER_FILES
llbase32.h
llbase64.h
llboost.h
+ llcallbacklist.h
llchat.h
llclickaction.h
llcommon.h
@@ -202,6 +213,7 @@ set(llcommon_HEADER_FILES
llrun.h
llsafehandle.h
llsd.h
+ llsdjson.h
llsdparam.h
llsdserialize.h
llsdserialize_xml.h
@@ -226,10 +238,14 @@ set(llcommon_HEADER_FILES
llthreadsafequeue.h
lltimer.h
lltreeiterators.h
+ llunits.h
+ llunittype.h
lltypeinfolookup.h
lluri.h
+ lluriparser.h
lluuid.h
- llversionviewer.h.in
+ llwin32headers.h
+ llwin32headerslean.h
llworkerthread.h
metaclass.h
metaclasst.h
@@ -249,19 +265,32 @@ set_source_files_properties(${llcommon_HEADER_FILES}
PROPERTIES HEADER_FILE_ONLY TRUE)
list(APPEND llcommon_SOURCE_FILES ${cwdebug_SOURCE_FILES})
+
list(APPEND llcommon_SOURCE_FILES ${llcommon_HEADER_FILES})
-add_library (llcommon SHARED ${llcommon_SOURCE_FILES})
-if(WINDOWS)
-set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL")
-endif(WINDOWS)
-add_dependencies(llcommon prepare)
+if(LLCOMMON_LINK_SHARED)
+ add_library (llcommon SHARED ${llcommon_SOURCE_FILES})
+ if(WINDOWS)
+ # always generate llcommon.pdb, even for "Release" builds
+ set_target_properties(llcommon PROPERTIES LINK_FLAGS "/DEBUG")
+ endif(WINDOWS)
+ ll_stage_sharedlib(llcommon)
+else(LLCOMMON_LINK_SHARED)
+ add_library (llcommon ${llcommon_SOURCE_FILES})
+endif(LLCOMMON_LINK_SHARED)
+
+set_target_properties(llcommon PROPERTIES POSITION_INDEPENDENT_CODE TRUE)
+
target_link_libraries(
llcommon
- ${BREAKPAD_EXCEPTION_HANDLER_LIBRARIES}
+ PUBLIC
+ absl::hash
${APRUTIL_LIBRARIES}
${APR_LIBRARIES}
${EXPAT_LIBRARIES}
+ ${CRYPTO_LIBRARIES}
+ ${OPENSSL_LIBRARIES}
+ ${CRYPTO_LIBRARIES}
${ZLIB_LIBRARIES}
${WINDOWS_LIBRARIES}
${Boost_CONTEXT_LIBRARY}
@@ -269,6 +298,11 @@ target_link_libraries(
${Boost_THREAD_LIBRARY}
${Boost_SYSTEM_LIBRARY}
${CORESERVICES_LIBRARY}
+ ${URIPARSER_LIBRARY}
+ fmt::fmt
+ nlohmann_json::nlohmann_json
+ absl::strings
+ ${RT_LIBRARY}
)
if (DARWIN)
@@ -280,3 +314,5 @@ if (DARWIN)
INSTALL_NAME_DIR "@executable_path/../Resources"
)
endif (DARWIN)
+
+add_dependencies(llcommon stage_third_party_libs)
diff --git a/indra/llcommon/aialert.h b/indra/llcommon/aialert.h
index 4d3704cfbc..17042cfcc3 100644
--- a/indra/llcommon/aialert.h
+++ b/indra/llcommon/aialert.h
@@ -132,7 +132,7 @@ class LL_COMMON_API AIArgs
// Add another replacement.
AIArgs& operator()(char const* key, std::string const& replacement) { mArgs[key] = replacement; return *this; }
// The destructor may not throw.
- ~AIArgs() throw() { }
+ ~AIArgs() noexcept { }
// Accessor.
LLStringUtil::format_map_t const& operator*() const { return mArgs; }
@@ -193,7 +193,7 @@ class LL_COMMON_API Line
Line(std::string const& xml_desc, AIArgs const& args, bool newline = false) : mNewline(newline), mXmlDesc(xml_desc), mArgs(args), mType(normal) { }
Line(Prefix const& prefix, bool newline = false) : mNewline(newline), mXmlDesc("AIPrefix"), mArgs("[PREFIX]", prefix.str()), mType(prefix.type()) { }
// The destructor may not throw.
- ~Line() throw() { }
+ ~Line() noexcept { }
// Prepend a newline before this line.
void set_newline(void) { mNewline = true; }
@@ -225,7 +225,7 @@ class LL_COMMON_API Error : public std::exception
typedef std::deque lines_type;
// The destructor may not throw.
- ~Error() throw() { }
+ ~Error() noexcept { }
// Accessors.
lines_type const& lines(void) const { return mLines; }
@@ -267,7 +267,7 @@ class LL_COMMON_API ErrorCode : public Error
public:
// The destructor may not throw.
- ~ErrorCode() throw() { }
+ ~ErrorCode() noexcept { }
// Accessor.
int getCode(void) const { return mCode; }
diff --git a/indra/llcommon/aifile.cpp b/indra/llcommon/aifile.cpp
deleted file mode 100644
index cd2ade77ab..0000000000
--- a/indra/llcommon/aifile.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-/**
- * @file aifile.cpp
- * @brief POSIX file operations that throw on error.
- *
- * Copyright (c) 2013, Aleric Inglewood.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution.
- *
- * CHANGELOG
- * and additional copyright holders.
- *
- * 03/11/2013
- * Initial version, written by Aleric Inglewood @ SL
- */
-
-#include "linden_common.h"
-#include "aifile.h"
-#include "aialert.h"
-
-#if LL_WINDOWS
-#include
-#include // Windows errno
-#else
-#include
-#endif
-
-AIFile::AIFile(std::string const& filename, char const* accessmode)
-{
- mFp = AIFile::fopen(filename, accessmode);
-}
-
-AIFile::~AIFile()
-{
- AIFile::close(mFp);
-}
-
-// Like THROW_MALERTE but appends "LLFile::strerr(errn) << " (" << errn << ')'" as argument to replace [ERROR].
-#define THROW_ERROR(...) \
- do { \
- int errn = errno; \
- std::ostringstream error; \
- error << LLFile::strerr(errn) << " (" << errn << ')'; \
- THROW_MALERT_CLASS(AIAlert::ErrorCode, errn, __VA_ARGS__ ("[ERROR]", error.str())); \
- } while(0)
-
-//static
-void AIFile::mkdir(std::string const& dirname, int perms)
-{
- int rc = LLFile::mkdir_nowarn(dirname, perms);
- if (rc < 0 && errno != EEXIST)
- {
- THROW_ERROR("AIFile_mkdir_Failed_to_create_DIRNAME", AIArgs("[DIRNAME]", dirname));
- }
-}
-
-//static
-void AIFile::rmdir(std::string const& dirname)
-{
- int rc = LLFile::rmdir_nowarn(dirname);
- if (rc < 0 && errno != ENOENT)
- {
- THROW_ERROR("AIFile_rmdir_Failed_to_remove_DIRNAME", AIArgs("[DIRNAME]", dirname));
- }
-}
-
-//static
-LLFILE* AIFile::fopen(std::string const& filename, const char* mode)
-{
- LLFILE* fp = LLFile::fopen(filename, mode);
- if (!fp)
- {
- THROW_ERROR("AIFile_fopen_Failed_to_open_FILENAME", AIArgs("[FILENAME]", filename));
- }
- return fp;
-}
-
-//static
-void AIFile::close(LLFILE* file)
-{
- if (LLFile::close(file) < 0)
- {
- THROW_ERROR("AIFile_close_Failed_to_close_file", AIArgs);
- }
-}
-
-//static
-void AIFile::remove(std::string const& filename)
-{
- int rc = LLFile::remove_nowarn(filename);
- if (rc < 0 && errno != ENOENT)
- {
- THROW_ERROR("AIFile_remove_Failed_to_remove_FILENAME", AIArgs("[FILENAME]", filename));
- }
-}
-
-//static
-void AIFile::rename(std::string const& filename, std::string const& newname)
-{
- if (LLFile::rename_nowarn(filename, newname) < 0)
- {
- THROW_ERROR("AIFile_rename_Failed_to_rename_FILE_to_NEWFILE", AIArgs("[FILE]", filename)("[NEWFILE]", newname));
- }
-}
-
diff --git a/indra/llcommon/aifile.h b/indra/llcommon/aifile.h
deleted file mode 100644
index 1b110496ae..0000000000
--- a/indra/llcommon/aifile.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- * @file aifile.h
- * @brief Declaration of AIFile.
- *
- * Copyright (c) 2013, Aleric Inglewood.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution.
- *
- * CHANGELOG
- * and additional copyright holders.
- *
- * 02/11/2013
- * Initial version, written by Aleric Inglewood @ SL
- */
-
-#ifndef AIFILE_H
-#define AIFILE_H
-
-#include "llfile.h"
-
-// As LLFile, but throws AIAlert instead of printing a warning.
-class LL_COMMON_API AIFile
-{
- private:
- LLFILE* mFp;
-
- public:
- // Scoped file (exception safe). Throws AIAlertCode with errno on failure.
- AIFile(std::string const& filename, char const* accessmode);
- ~AIFile();
-
- operator LLFILE* () const { return mFp; }
-
- // All these functions take UTF8 path/filenames.
- static LLFILE* fopen(std::string const& filename, char const* accessmode);
- static void close(LLFILE* file);
-
- static void mkdir(std::string const& dirname, int perms = 0700); // Does NOT throw when dirname already exists.
- static void rmdir(std::string const& dirname); // Does NOT throw when dirname does not exist.
- static void remove(std::string const& filename); // Does NOT throw when filename does not exist.
- static void rename(std::string const& filename, std::string const& newname);
-};
-
-#endif // AIFILE_H
diff --git a/indra/llcommon/aisyncclient.cpp b/indra/llcommon/aisyncclient.cpp
index c62d88efb6..191a2627d4 100644
--- a/indra/llcommon/aisyncclient.cpp
+++ b/indra/llcommon/aisyncclient.cpp
@@ -90,7 +90,7 @@
bool operator==(AISyncKey const& key1, AISyncKey const& key2)
{
// Test if these keys match based on time.
- if (std::abs((S32)(key1.mStartFrameCount - key2.mStartFrameCount)) > 1 &&
+ if (std::abs((S64)(key1.mStartFrameCount - key2.mStartFrameCount)) > 1 &&
std::abs(key1.mFrameTimer.getStartTime() - key2.mFrameTimer.getStartTime()) >= sSyncKeyExpirationTime)
{
return false;
@@ -420,7 +420,7 @@ void AISyncServerMap::remove_server(AISyncServer* server)
#include
//static
-U32 LLFrameTimer::sFrameCount;
+U64 LLFrameTimer::sFrameCount;
double innerloop_count = 0;
diff --git a/indra/llcommon/aisyncclient.h b/indra/llcommon/aisyncclient.h
index 0f5237f99e..eecad2924d 100644
--- a/indra/llcommon/aisyncclient.h
+++ b/indra/llcommon/aisyncclient.h
@@ -56,8 +56,8 @@ struct LLFrameTimer
double mStartTime;
double mExpiry;
static double getCurrentTime(void);
- static U32 sFrameCount;
- static U32 getFrameCount() { return sFrameCount; }
+ static U64 sFrameCount;
+ static U64 getFrameCount() { return sFrameCount; }
F64 getStartTime() const { return mStartTime; }
void reset(double expiration) { mStartTime = getCurrentTime(); mExpiry = mStartTime + expiration; }
bool hasExpired(void) const { return getCurrentTime() > mExpiry; }
@@ -114,7 +114,7 @@ class LL_COMMON_API AISyncKey
{
private:
LLFrameTimer mFrameTimer; // This timer is started at the moment the sync key is created.
- U32 mStartFrameCount; // The frame count at which the timer was started.
+ U64 mStartFrameCount; // The frame count at which the timer was started.
public:
// Constructor.
diff --git a/indra/llcommon/aithreadsafe.h b/indra/llcommon/aithreadsafe.h
index 93b38246fb..ac1531596e 100644
--- a/indra/llcommon/aithreadsafe.h
+++ b/indra/llcommon/aithreadsafe.h
@@ -96,16 +96,6 @@
#include "llthread.h"
#include "llerror.h"
-// g++ 4.2.x (and before?) have the bug that when you try to pass a temporary
-// to a function taking a const reference, it still calls the copy constructor.
-// Define this to hack around that.
-// Note that the chosen solution ONLY works for copying an AI*Access object that
-// is passed to a function: the lifetime of the copied object must not be longer
-// than the original (or at least, it shouldn't be used anymore after the
-// original is destructed). This will be guaranteed if the code also compiles
-// on a compiler that doesn't need this hack.
-#define AI_NEED_ACCESS_CC (defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ < 3)) || (__GNUC__ < 4)))
-
template struct AIReadAccessConst;
template struct AIReadAccess;
template struct AIWriteAccess;
@@ -339,9 +329,6 @@ struct AIReadAccessConst
AIReadAccessConst(AIThreadSafe const& wrapper, bool high_priority = false)
: mWrapper(const_cast&>(wrapper)),
mState(readlocked)
-#if AI_NEED_ACCESS_CC
- , mIsCopyConstructed(false)
-#endif
{
mWrapper.mRWLock.rdlock(high_priority);
}
@@ -350,9 +337,6 @@ struct AIReadAccessConst
// These should never be dynamically allocated, so there is no need to make this virtual.
~AIReadAccessConst()
{
-#if AI_NEED_ACCESS_CC
- if (mIsCopyConstructed) return;
-#endif
if (mState == readlocked)
mWrapper.mRWLock.rdunlock();
else if (mState == writelocked)
@@ -371,23 +355,14 @@ struct AIReadAccessConst
//! Constructor used by AIReadAccess.
AIReadAccessConst(AIThreadSafe& wrapper, state_type state)
: mWrapper(wrapper), mState(state)
-#if AI_NEED_ACCESS_CC
- , mIsCopyConstructed(false)
-#endif
{ }
AIThreadSafe& mWrapper; //!< Reference to the object that we provide access to.
state_type const mState; //!< The lock state that mWrapper is in.
-#if AI_NEED_ACCESS_CC
- bool mIsCopyConstructed;
-public:
- AIReadAccessConst(AIReadAccessConst const& orig) : mWrapper(orig.mWrapper), mState(orig.mState), mIsCopyConstructed(true) { }
-#else
private:
// Disallow copy constructing directly.
AIReadAccessConst(AIReadAccessConst const&);
-#endif
};
/**
@@ -596,9 +571,6 @@ struct AIAccessConst
{
//! Construct a AIAccessConst from a constant AIThreadSafeSimple.
AIAccessConst(AIThreadSafeSimple const& wrapper) : mWrapper(const_cast&>(wrapper))
-#if AI_NEED_ACCESS_CC
- , mIsCopyConstructed(false)
-#endif
{
this->mWrapper.mMutex.lock();
}
@@ -611,9 +583,6 @@ struct AIAccessConst
~AIAccessConst()
{
-#if AI_NEED_ACCESS_CC
- if (mIsCopyConstructed) return;
-#endif
this->mWrapper.mMutex.unlock();
}
@@ -625,15 +594,9 @@ struct AIAccessConst
protected:
AIThreadSafeSimple& mWrapper; //!< Reference to the object that we provide access to.
-#if AI_NEED_ACCESS_CC
- bool mIsCopyConstructed;
-public:
- AIAccessConst(AIAccessConst const& orig) : mWrapper(orig.mWrapper), mIsCopyConstructed(true) { }
-#else
private:
// Disallow copy constructing directly.
AIAccessConst(AIAccessConst const&);
-#endif
};
/**
@@ -817,14 +780,9 @@ struct AISTAccessConst
protected:
AIThreadSafeSingleThread& mWrapper; //!< Reference to the object that we provide access to.
-#if AI_NEED_ACCESS_CC
-public:
- AISTAccessConst(AISTAccessConst const& orig) : mWrapper(orig.mWrapper) { }
-#else
private:
// Disallow copy constructing directly.
AISTAccessConst(AISTAccessConst const&);
-#endif
};
/**
diff --git a/indra/llcommon/indra_constants.cpp b/indra/llcommon/indra_constants.cpp
index 64cbb1131c..daef52756b 100644
--- a/indra/llcommon/indra_constants.cpp
+++ b/indra/llcommon/indra_constants.cpp
@@ -45,3 +45,15 @@ const LLUUID GOVERNOR_LINDEN_ID("3d6181b0-6a4b-97ef-18d8-722652995cf1");
const LLUUID REALESTATE_LINDEN_ID("3d6181b0-6a4b-97ef-18d8-722652995cf1");
// Maintenance's group id.
const LLUUID MAINTENANCE_GROUP_ID("dc7b21cd-3c89-fcaa-31c8-25f9ffd224cd");
+
+const LLUUID IMG_USE_BAKED_HEAD ("5a9f4a74-30f2-821c-b88d-70499d3e7183");
+const LLUUID IMG_USE_BAKED_UPPER ("ae2de45c-d252-50b8-5c6e-19f39ce79317");
+const LLUUID IMG_USE_BAKED_LOWER ("24daea5f-0539-cfcf-047f-fbc40b2786ba");
+const LLUUID IMG_USE_BAKED_EYES ("52cc6bb6-2ee5-e632-d3ad-50197b1dcb8a");
+const LLUUID IMG_USE_BAKED_SKIRT ("43529ce8-7faa-ad92-165a-bc4078371687");
+const LLUUID IMG_USE_BAKED_HAIR ("09aac1fb-6bce-0bee-7d44-caac6dbb6c63");
+const LLUUID IMG_USE_BAKED_LEFTARM ("ff62763f-d60a-9855-890b-0c96f8f8cd98");
+const LLUUID IMG_USE_BAKED_LEFTLEG ("8e915e25-31d1-cc95-ae08-d58a47488251");
+const LLUUID IMG_USE_BAKED_AUX1 ("9742065b-19b5-297c-858a-29711d539043");
+const LLUUID IMG_USE_BAKED_AUX2 ("03642e83-2bd1-4eb9-34b4-4c47ed586d2d");
+const LLUUID IMG_USE_BAKED_AUX3 ("edd51b77-fc10-ce7a-4b3d-011dfc349e4f");
diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h
index 7e7bdaa85c..786e1bbd26 100644
--- a/indra/llcommon/indra_constants.h
+++ b/indra/llcommon/indra_constants.h
@@ -1,3 +1,4 @@
+
/**
* @file indra_constants.h
* @brief some useful short term constants for Indra
@@ -32,15 +33,6 @@
class LLUUID;
-// At 45 Hz collisions seem stable and objects seem
-// to settle down at a reasonable rate.
-// JC 3/18/2003
-
-// const F32 PHYSICS_TIMESTEP = 1.f / 45.f;
-// This must be a #define due to anal retentive restrictions on const expressions
-// CG 2008-06-05
-#define PHYSICS_TIMESTEP (1.f / 45.f)
-
const F32 COLLISION_TOLERANCE = 0.1f;
const F32 HALF_COLLISION_TOLERANCE = 0.05f;
@@ -140,18 +132,18 @@ const U32 DEFAULT_CGI_SERVICES_PORT = 12045;
// on a single host for map tile generation. JC
const U32 DEFAULT_MAPSERVER_PORT = 12124;
-const char LAND_LAYER_CODE = 'L';
-const char WATER_LAYER_CODE = 'W';
-const char WIND_LAYER_CODE = '7';
-const char CLOUD_LAYER_CODE = '8';
-
-// Aurora Sim
-// Extended land layer for Aurora Sim
-const char AURORA_LAND_LAYER_CODE = 'M';
-const char AURORA_WATER_LAYER_CODE = 'X';
-const char AURORA_WIND_LAYER_CODE = '9';
-const char AURORA_CLOUD_LAYER_CODE = ':';
-// Aurora Sim
+enum ETerrainBrushType
+{
+ // the valid brush numbers cannot be reordered, because they
+ // are used in the binary LSL format as arguments to llModifyLand()
+ E_LANDBRUSH_LEVEL = 0,
+ E_LANDBRUSH_RAISE = 1,
+ E_LANDBRUSH_LOWER = 2,
+ E_LANDBRUSH_SMOOTH = 3,
+ E_LANDBRUSH_NOISE = 4,
+ E_LANDBRUSH_REVERT = 5,
+ E_LANDBRUSH_INVALID = 6
+};
// keys
// Bit masks for various keyboard modifier keys.
@@ -252,7 +244,6 @@ const U8 SIM_ACCESS_DOWN = 254;
const U8 SIM_ACCESS_MAX = SIM_ACCESS_ADULT;
// attachment constants
-const S32 MAX_AGENT_ATTACHMENTS = 38;
const U8 ATTACHMENT_ADD = 0x80;
// god levels
@@ -303,13 +294,18 @@ const U32 START_LOCATION_ID_COUNT = 6;
// group constants
const U32 GROUP_MIN_SIZE = 2;
-// gMaxAgentGroups is now sent by login.cgi, which
-// looks it up from globals.xml.
-//
-// For now we need an old default value however,
-// so the viewer can be deployed ahead of login.cgi.
-//
-const S32 DEFAULT_MAX_AGENT_GROUPS = 25;
+
+LL_COMMON_API extern const LLUUID IMG_USE_BAKED_HEAD;
+LL_COMMON_API extern const LLUUID IMG_USE_BAKED_UPPER;
+LL_COMMON_API extern const LLUUID IMG_USE_BAKED_LOWER;
+LL_COMMON_API extern const LLUUID IMG_USE_BAKED_EYES;
+LL_COMMON_API extern const LLUUID IMG_USE_BAKED_SKIRT;
+LL_COMMON_API extern const LLUUID IMG_USE_BAKED_HAIR;
+LL_COMMON_API extern const LLUUID IMG_USE_BAKED_LEFTARM;
+LL_COMMON_API extern const LLUUID IMG_USE_BAKED_LEFTLEG;
+LL_COMMON_API extern const LLUUID IMG_USE_BAKED_AUX1;
+LL_COMMON_API extern const LLUUID IMG_USE_BAKED_AUX2;
+LL_COMMON_API extern const LLUUID IMG_USE_BAKED_AUX3;
// radius within which a chat message is fully audible
const F32 CHAT_WHISPER_RADIUS = 10.f;
@@ -341,18 +337,7 @@ const S32 SANDBOX_CLEAN_FREQ = 12;
const F32 WIND_SCALE_HACK = 2.0f; // hack to make wind speeds more realistic
-enum ETerrainBrushType
-{
- // the valid brush numbers cannot be reordered, because they
- // are used in the binary LSL format as arguments to llModifyLand()
- E_LANDBRUSH_LEVEL = 0,
- E_LANDBRUSH_RAISE = 1,
- E_LANDBRUSH_LOWER = 2,
- E_LANDBRUSH_SMOOTH = 3,
- E_LANDBRUSH_NOISE = 4,
- E_LANDBRUSH_REVERT = 5,
- E_LANDBRUSH_INVALID = 6
-};
+
// media commands
const U32 PARCEL_MEDIA_COMMAND_STOP = 0;
@@ -382,13 +367,6 @@ const U32 MAP_ITEM_CLASSIFIED = 0x08;
const U32 MAP_ITEM_ADULT_EVENT = 0x09;
const U32 MAP_ITEM_LAND_FOR_SALE_ADULT = 0x0a;
-// Crash reporter behavior
-const char* const CRASH_SETTINGS_FILE = "settings_crash_behavior.xml";
-const char* const CRASH_BEHAVIOR_SETTING = "CrashSubmitBehavior";
-const S32 CRASH_BEHAVIOR_ASK = 0;
-const S32 CRASH_BEHAVIOR_ALWAYS_SEND = 1;
-const S32 CRASH_BEHAVIOR_NEVER_SEND = 2;
-
// Export/Import return values
const S32 EXPORT_SUCCESS = 0;
const S32 EXPORT_ERROR_PERMISSIONS = -1;
diff --git a/indra/llcommon/is_approx_equal_fraction.h b/indra/llcommon/is_approx_equal_fraction.h
index d369fbc5b3..3c7f4e9282 100644
--- a/indra/llcommon/is_approx_equal_fraction.h
+++ b/indra/llcommon/is_approx_equal_fraction.h
@@ -49,9 +49,8 @@
* signatures.
*/
template
-inline BOOL is_approx_equal_fraction_impl(FTYPE x, FTYPE y, U32 frac_bits)
+inline bool is_approx_equal_fraction_impl(FTYPE x, FTYPE y, U32 frac_bits)
{
- BOOL ret = TRUE;
FTYPE diff = (FTYPE) fabs(x - y);
S32 diffInt = (S32) diff;
@@ -64,20 +63,20 @@ inline BOOL is_approx_equal_fraction_impl(FTYPE x, FTYPE y, U32 frac_bits)
// based on the number of bits used for packing decimal portion.
if (diffInt != 0 || diffFracTolerance > 1)
{
- ret = FALSE;
+ return false;
}
- return ret;
+ return true;
}
/// F32 flavor
-inline BOOL is_approx_equal_fraction(F32 x, F32 y, U32 frac_bits)
+inline bool is_approx_equal_fraction(F32 x, F32 y, U32 frac_bits)
{
return is_approx_equal_fraction_impl(x, y, frac_bits);
}
/// F64 flavor
-inline BOOL is_approx_equal_fraction(F64 x, F64 y, U32 frac_bits)
+inline bool is_approx_equal_fraction(F64 x, F64 y, U32 frac_bits)
{
return is_approx_equal_fraction_impl(x, y, frac_bits);
}
diff --git a/indra/llcommon/linden_common.h b/indra/llcommon/linden_common.h
index b5e9de73d5..d44c318477 100644
--- a/indra/llcommon/linden_common.h
+++ b/indra/llcommon/linden_common.h
@@ -43,11 +43,9 @@
#endif
#if defined(LL_WINDOWS) && defined(_DEBUG)
-# if _MSC_VER >= 1400 // Visual C++ 2005 or later
# define _CRTDBG_MAP_ALLOC
# include
# include
-# endif
#endif
#include "llpreprocessor.h"
@@ -68,5 +66,6 @@
#include "lldefs.h"
#include "llerror.h"
#include "llfile.h"
+#include "llformat.h"
#endif
diff --git a/indra/llcommon/llalignedarray.h b/indra/llcommon/llalignedarray.h
index 14e25e78d6..d6ab5ed3dc 100644
--- a/indra/llcommon/llalignedarray.h
+++ b/indra/llcommon/llalignedarray.h
@@ -64,7 +64,7 @@ LLAlignedArray::LLAlignedArray()
template
LLAlignedArray::~LLAlignedArray()
{
- ll_aligned_free(mArray);
+ ll_aligned_free(mArray);
mArray = NULL;
mElementCount = 0;
mCapacity = 0;
@@ -78,7 +78,7 @@ void LLAlignedArray::push_back(const T& elem)
{
mCapacity++;
mCapacity *= 2;
- T* new_buf = (T*) ll_aligned_malloc(mCapacity*sizeof(T), alignment);
+ T* new_buf = (T*) ll_aligned_malloc(mCapacity*sizeof(T));
if (mArray)
{
ll_memcpy_nonaliased_aligned_16((char*)new_buf, (char*)mArray, sizeof(T)*mElementCount);
@@ -90,7 +90,7 @@ void LLAlignedArray::push_back(const T& elem)
mArray[mElementCount++] = elem;
//delete old array here to prevent error on a.push_back(a[0])
- ll_aligned_free(old_buf);
+ ll_aligned_free(old_buf);
}
template
@@ -99,11 +99,11 @@ void LLAlignedArray::resize(U32 size)
if (mCapacity < size)
{
mCapacity = size+mCapacity*2;
- T* new_buf = mCapacity > 0 ? (T*) ll_aligned_malloc(mCapacity*sizeof(T), alignment) : NULL;
+ T* new_buf = mCapacity > 0 ? (T*) ll_aligned_malloc(mCapacity*sizeof(T)) : NULL;
if (mArray)
{
ll_memcpy_nonaliased_aligned_16((char*) new_buf, (char*) mArray, sizeof(T)*mElementCount);
- ll_aligned_free(mArray);
+ ll_aligned_free(mArray);
}
/*for (U32 i = mElementCount; i < mCapacity; ++i)
diff --git a/indra/llcommon/llallocator_heap_profile.cpp b/indra/llcommon/llallocator_heap_profile.cpp
index b2eafde1aa..499d78ed64 100644
--- a/indra/llcommon/llallocator_heap_profile.cpp
+++ b/indra/llcommon/llallocator_heap_profile.cpp
@@ -40,7 +40,7 @@
#include
#include
-static const std::string HEAP_PROFILE_MAGIC_STR = "heap profile:";
+static const std::string HEAP_PROFILE_MAGIC_STR("heap profile:");
static bool is_separator(char c)
{
@@ -70,7 +70,7 @@ void LLAllocatorHeapProfile::parse(std::string const & prof_text)
range_t prof_range(prof_begin, prof_text.end());
boost::algorithm::split(prof_lines,
prof_range,
- boost::bind(std::equal_to(), '\n', _1));
+ std::bind(std::equal_to(), '\n', std::placeholders::_1));
std::vector< range_t >::const_iterator i;
for(i = prof_lines.begin(); i != prof_lines.end() && !i->empty(); ++i)
diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp
index bc3e7196d5..36c6b0f611 100644
--- a/indra/llcommon/llapp.cpp
+++ b/indra/llcommon/llapp.cpp
@@ -25,9 +25,8 @@
*/
#include "linden_common.h"
-#include "llapp.h"
-#include
+#include "llapp.h"
#ifdef LL_DARWIN
#include
@@ -45,7 +44,6 @@
#include "llstl.h" // for DeletePointer()
#include "llstring.h"
#include "lleventtimer.h"
-#include "exception_handler.h"
//
// Signal handling
@@ -53,16 +51,10 @@
// Windows uses structured exceptions, so it's handled a bit differently.
//
#if LL_WINDOWS
-#include "windows.h"
+#include
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
# include // for fork()
@@ -70,18 +62,6 @@ bool windows_post_minidump_callback(const wchar_t* dump_path,
void setup_signals();
void default_unix_signal_handler(int signum, siginfo_t *info, void *);
-#if LL_LINUX
-#include "client/linux/handler/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,
- const char *minidump_id,
- void *context, bool succeeded);
-#endif
-
# if LL_DARWIN
/* OSX doesn't support SIGRT* */
S32 LL_SMACKDOWN_SIGNAL = SIGUSR1;
@@ -98,7 +78,7 @@ S32 LL_HEARTBEAT_SIGNAL = (SIGRTMAX >= 0) ? (SIGRTMAX-0) : SIGUSR2;
#endif // LL_WINDOWS
// the static application instance
-LLApp* LLApp::sApplication = NULL;
+LLApp* LLApp::sApplication = nullptr;
// Allows the generation of core files for post mortem under gdb
// and disables crashlogger
@@ -110,7 +90,7 @@ BOOL LLApp::sLogInSignal = FALSE;
// static
LLApp::EAppStatus LLApp::sStatus = LLApp::APP_STATUS_STOPPED; // Keeps track of application status
-LLAppErrorHandler LLApp::sErrorHandler = NULL;
+LLAppErrorHandler LLApp::sErrorHandler = nullptr;
BOOL LLApp::sErrorThreadRunning = FALSE;
#if !LL_WINDOWS
LLApp::child_map LLApp::sChildMap;
@@ -119,13 +99,12 @@ LLAppChildCallback LLApp::sDefaultChildCallback = NULL;
#endif
-LLApp::LLApp() : mThreadErrorp(NULL)
+LLApp::LLApp()
+ : mThreadErrorp(nullptr)
{
commonCtor();
}
-static void* sCrashLoggerReserve = NULL;
-
void LLApp::commonCtor()
{
// Set our status to running
@@ -150,34 +129,11 @@ void LLApp::commonCtor()
// Set the application to this instance.
sApplication = this;
- mExceptionHandler = 0;
-
-#if LL_WINDOWS
- sCrashLoggerReserve = VirtualAlloc(NULL, 512*1024, MEM_COMMIT|MEM_RESERVE, PAGE_NOACCESS);
-#else
- sCrashLoggerReserve = malloc(512*1024);
-#endif
-
// initialize the buffer to write the minidump filename to
// (this is used to avoid allocating memory in the crash handler)
- memset(mMinidumpPath, 0, MAX_MINDUMP_PATH_LENGTH);
mCrashReportPipeStr = L"\\\\.\\pipe\\LLCrashReporterPipe";
}
-#if LL_WINDOWS
-static bool clear_CrashLoggerReserve_callback(void* context, EXCEPTION_POINTERS* exinfo, MDRawAssertionInfo* assertion)
-{
- VirtualFree(sCrashLoggerReserve, 0, MEM_RELEASE);
- return true;
-}
-#else
-static bool clear_CrashLoggerReserve_callback(void* context)
-{
- free(sCrashLoggerReserve);
- return true;
-}
-#endif
-
LLApp::LLApp(LLErrorThread *error_thread) :
mThreadErrorp(error_thread)
{
@@ -198,11 +154,9 @@ LLApp::~LLApp()
if (mThreadErrorp)
{
delete mThreadErrorp;
- mThreadErrorp = NULL;
+ mThreadErrorp = nullptr;
}
- if(mExceptionHandler != 0) delete mExceptionHandler;
-
LLCommon::cleanupClass();
}
@@ -216,8 +170,8 @@ LLApp* LLApp::instance()
LLSD LLApp::getOption(const std::string& name) const
{
LLSD rv;
- LLSD::array_const_iterator iter = mOptions.beginArray();
- LLSD::array_const_iterator end = mOptions.endArray();
+ auto iter = mOptions.beginArray();
+ auto end = mOptions.endArray();
for(; iter != end; ++iter)
{
rv = (*iter)[name];
@@ -264,9 +218,9 @@ bool LLApp::parseCommandOptions(int argc, char** argv)
#if LL_WINDOWS
//Windows changed command line parsing. Deal with it.
- S32 slen = value.length() - 1;
- S32 start = 0;
- S32 end = slen;
+ size_t slen = value.length() - 1;
+ size_t start = 0;
+ size_t end = slen;
if (argv[ii][start]=='"')start++;
if (argv[ii][end]=='"')end--;
if (start!=0 || end!=slen)
@@ -311,99 +265,49 @@ LLSD LLApp::getOptionData(OptionPriority level)
return mOptions[level];
}
-void LLApp::setupErrorHandling()
-{
- // Error handling is done by starting up an error handling thread, which just sleeps and
- // occasionally checks to see if the app is in an error state, and sees if it needs to be run.
-
#if LL_WINDOWS
- // Windows doesn't have the same signal handling mechanisms as UNIX, thus APR doesn't provide
- // a signal handling thread implementation.
- // What we do is install an unhandled exception handler, which will try to do the right thing
- // in the case of an error (generate a minidump)
-
-#if LL_SEND_CRASH_REPORTS
- // 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)
- {
- mExceptionHandler = new google_breakpad::ExceptionHandler(
- std::wstring(mDumpPath.begin(),mDumpPath.end()), //Dump path
- clear_CrashLoggerReserve_callback,
- windows_post_minidump_callback,
- 0,
- google_breakpad::ExceptionHandler::HANDLER_ALL);
- if (mExceptionHandler)
+//The following code is needed for 32-bit apps on 64-bit windows to keep it from eating
+//crashes. It is a lovely undocumented 'feature' in SP1 of Windows 7. An excellent
+//in-depth article on the issue may be found here: http://randomascii.wordpress.com/2012/07/05/when-even-crashing-doesn-work/
+void EnableCrashingOnCrashes()
+{
+ typedef BOOL (WINAPI *tGetPolicy)(LPDWORD lpFlags);
+ typedef BOOL (WINAPI *tSetPolicy)(DWORD dwFlags);
+ const DWORD EXCEPTION_SWALLOWING = 0x1;
+
+ HMODULE kernel32 = LoadLibraryA("kernel32.dll");
+ tGetPolicy pGetPolicy = (tGetPolicy)GetProcAddress(kernel32,
+ "GetProcessUserModeExceptionPolicy");
+ tSetPolicy pSetPolicy = (tSetPolicy)GetProcAddress(kernel32,
+ "SetProcessUserModeExceptionPolicy");
+ if (pGetPolicy && pSetPolicy)
+ {
+ DWORD dwFlags;
+ if (pGetPolicy(&dwFlags))
{
- mExceptionHandler->set_handle_debug_exceptions(true);
+ // Turn off the filter
+ pSetPolicy(dwFlags & ~EXCEPTION_SWALLOWING);
}
}
+}
#endif
-#else
+
+void LLApp::setupErrorHandling()
+{
+ // Error handling is done by starting up an error handling thread, which just sleeps and
+ // occasionally checks to see if the app is in an error state, and sees if it needs to be run.
+
+#if !LL_WINDOWS
//
// 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 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;
- }
-
- if(installHandler && (mExceptionHandler == 0))
- {
- mExceptionHandler = new google_breakpad::ExceptionHandler(mDumpPath, clear_CrashLoggerReserve_callback, &unix_post_minidump_callback, 0, true, 0);
- }
- #endif
-#elif LL_LINUX
- if(installHandler && (mExceptionHandler == 0))
- {
- if (mDumpPath.empty())
- {
- mDumpPath = "/tmp";
- }
- google_breakpad::MinidumpDescriptor desc(mDumpPath);
- mExceptionHandler = new google_breakpad::ExceptionHandler(desc, clear_CrashLoggerReserve_callback, unix_minidump_callback, NULL, true, -1);
- }
-#endif
-
+#endif // ! LL_WINDOWS
+#if !defined(USE_CRASHPAD)
+ startErrorThread();
#endif
}
@@ -441,7 +345,6 @@ void LLApp::setErrorHandler(LLAppErrorHandler handler)
LLApp::sErrorHandler = handler;
}
-
// static
void LLApp::runErrorHandler()
{
@@ -454,7 +357,6 @@ void LLApp::runErrorHandler()
LLApp::setStopped();
}
-
// static
void LLApp::setStatus(EAppStatus status)
{
@@ -469,43 +371,12 @@ void LLApp::setError()
setStatus(APP_STATUS_ERROR);
}
-void LLApp::setMiniDumpDir(const std::string &path)
-{
- if (path.empty())
- {
- mDumpPath = "/tmp";
- }
- else
- {
- mDumpPath = path;
- }
-
- if(mExceptionHandler == 0) return;
-#ifdef LL_WINDOWS
- wchar_t buffer[MAX_MINDUMP_PATH_LENGTH];
- mbstowcs(buffer, mDumpPath.c_str(), MAX_MINDUMP_PATH_LENGTH);
- mExceptionHandler->set_dump_path(std::wstring(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
-}
-
void LLApp::setDebugFileNames(const std::string &path)
{
mStaticDebugFileName = path + "static_debug_info.log";
mDynamicDebugFileName = path + "dynamic_debug_info.log";
}
-void LLApp::writeMiniDump()
-{
- if(mExceptionHandler == 0) return;
- mExceptionHandler->WriteMinidump();
-}
-
// static
void LLApp::setQuitting()
{
@@ -560,13 +431,6 @@ bool LLApp::isExiting()
void LLApp::disableCrashlogger()
{
- // Disable Breakpad exception handler.
- if (mExceptionHandler != 0)
- {
- delete mExceptionHandler;
- mExceptionHandler = 0;
- }
-
sDisableCrashlogger = TRUE;
}
@@ -635,12 +499,6 @@ LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *except
ms_sleep(10);
}
- //
- // Generate a minidump if we can.
- //
- // TODO: This needs to be ported over form the viewer-specific
- // LLWinDebug class
-
//
// At this point, we always want to exit the app. There's no graceful
// recovery for an unhandled exception.
@@ -940,150 +798,4 @@ 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: /.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() << "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)
-{
- // Copy minidump file path into fixed buffer in the app instance to avoid
- // heap allocations in a crash handler.
-
- // path format: /.dmp
- int dirPathLength = strlen(dump_dir);
- int idLength = strlen(minidump_id);
-
- // The path must not be truncated.
- llassert((dirPathLength + idLength + 5) <= LLApp::MAX_MINDUMP_PATH_LENGTH);
-
- char * path = LLApp::instance()->getMiniDumpFilename();
- S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH;
- strncpy(path, dump_dir, remaining);
- remaining -= dirPathLength;
- path += dirPathLength;
- if (remaining > 0 && dirPathLength > 0 && path[-1] != '/')
- {
- *path++ = '/';
- --remaining;
- }
- if (remaining > 0)
- {
- strncpy(path, minidump_id, remaining);
- remaining -= idLength;
- path += idLength;
- strncpy(path, ".dmp", remaining);
- }
-
- LL_INFOS() << "generated minidump: " << path << LL_ENDL;
- LLApp::runErrorHandler();
-
-#ifndef LL_RELEASE_FOR_DOWNLOAD
- clear_signals();
- return false;
-#else
- return true;
-#endif
-}
#endif // !WINDOWS
-
-#ifdef LL_WINDOWS
-bool windows_post_minidump_callback(const wchar_t* dump_path,
- const wchar_t* minidump_id,
- void* context,
- EXCEPTION_POINTERS* exinfo,
- MDRawAssertionInfo* assertion,
- bool succeeded)
-{
- char * path = LLApp::instance()->getMiniDumpFilename();
- S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH;
- size_t bytesUsed;
-
- bytesUsed = wcstombs(path, dump_path, static_cast(remaining));
- remaining -= bytesUsed;
- path += bytesUsed;
- if(remaining > 0 && bytesUsed > 0 && path[-1] != '\\')
- {
- *path++ = '\\';
- --remaining;
- }
- if(remaining > 0)
- {
- bytesUsed = wcstombs(path, minidump_id, static_cast(remaining));
- remaining -= bytesUsed;
- path += bytesUsed;
- }
- if(remaining > 0)
- {
- strncpy(path, ".dmp", remaining);
- }
-
- LL_INFOS() << "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
diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h
index aab871799c..2a8fddfa23 100644
--- a/indra/llcommon/llapp.h
+++ b/indra/llcommon/llapp.h
@@ -60,10 +60,6 @@ class LLChildInfo
};
#endif
-namespace google_breakpad {
- class ExceptionHandler; // See exception_handler.h
-}
-
class LL_COMMON_API LLApp : public LLOptionInterface
{
friend class LLErrorThread;
@@ -233,22 +229,11 @@ class LL_COMMON_API LLApp : public LLOptionInterface
static void runErrorHandler(); // run shortly after we detect an error, ran in the relatively robust context of the LLErrorThread - preferred.
//@}
- // the maximum length of the minidump filename returned by getMiniDumpFilename()
- 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; }
- // Write out a Google Breakpad minidump file.
- void writeMiniDump();
-
-
#if !LL_WINDOWS
//
// Child process handling (Unix only for now)
@@ -281,8 +266,6 @@ class LL_COMMON_API LLApp : public LLOptionInterface
static BOOL sDisableCrashlogger; // Let the OS handle crashes for us.
std::wstring mCrashReportPipeStr; //Name of pipe to use for crash reporting.
- std::string mDumpPath; //output path for google breakpad. Dependency workaround.
-
#if !LL_WINDOWS
static LLAtomicU32* sSigChildCount; // Number of SIGCHLDs received.
typedef std::map child_map; // Map key is a PID
@@ -290,16 +273,13 @@ class LL_COMMON_API LLApp : public LLOptionInterface
static LLAppChildCallback sDefaultChildCallback;
#endif
- void startErrorThread();
-
/**
* @brief This method is called at the end, just prior to deinitializing curl.
*/
void stopErrorThread();
private:
- // Contains the filename of the minidump file after a crash.
- char mMinidumpPath[MAX_MINDUMP_PATH_LENGTH];
+ void startErrorThread();
std::string mStaticDebugFileName;
std::string mDynamicDebugFileName;
@@ -323,11 +303,8 @@ class LL_COMMON_API LLApp : public LLOptionInterface
std::vector mLiveFiles;
//@}
-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 *);
diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp
index de7f3e9dca..a1a445261a 100644
--- a/indra/llcommon/llapr.cpp
+++ b/indra/llcommon/llapr.cpp
@@ -29,6 +29,7 @@
#include "linden_common.h"
#include "llapr.h"
#include "llscopedvolatileaprpool.h"
+#include
bool ll_apr_warn_status(apr_status_t status)
{
@@ -150,7 +151,7 @@ apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, BOO
return open(filename, flags, use_global_pool ? LLAPRFile::long_lived : LLAPRFile::short_lived);
}
// File I/O
-S32 LLAPRFile::read(void *buf, S32 nbytes)
+S32 LLAPRFile::read(void *buf, U64 nbytes)
{
if(!mFile)
{
@@ -167,12 +168,12 @@ S32 LLAPRFile::read(void *buf, S32 nbytes)
}
else
{
- llassert_always(sz <= 0x7fffffff);
+ llassert_always(sz <= std::numeric_limits::max());
return (S32)sz;
}
}
-S32 LLAPRFile::write(const void *buf, S32 nbytes)
+S32 LLAPRFile::write(const void *buf, U64 nbytes)
{
if(!mFile)
{
@@ -189,7 +190,7 @@ S32 LLAPRFile::write(const void *buf, S32 nbytes)
}
else
{
- llassert_always(sz <= 0x7fffffff);
+ llassert_always(sz <= std::numeric_limits::max());
return (S32)sz;
}
}
diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h
index 9baddef5ff..03a010d6c4 100644
--- a/indra/llcommon/llapr.h
+++ b/indra/llcommon/llapr.h
@@ -33,6 +33,8 @@
#include |