From 23811df3cf466928a19e93e2587038159ec03fdf Mon Sep 17 00:00:00 2001
From: Drake Arconis
Date: Sun, 19 Feb 2012 06:43:04 -0500
Subject: [PATCH 1/9] Adding to Ignore.
---
.gitignore | 1 +
1 file changed, 1 insertion(+)
diff --git a/.gitignore b/.gitignore
index bfe820c87..c56bf2a54 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,6 +18,7 @@
*.rej
*.bak
*~
+*.DS_Store
/LICENSES/
/edited-files.txt
qtcreator-build/
From 925c42294f451b1118f6d8e5183364329d360ce3 Mon Sep 17 00:00:00 2001
From: Drake Arconis
Date: Sun, 19 Feb 2012 11:30:27 -0500
Subject: [PATCH 2/9] OS X Builds now.
Fixed building on OS X.
Fixed line endings.
Need to find better way to do fmodwrapper thing.
---
indra/newview/fmodwrapper.cpp | 22 +-
indra/newview/llstartup.cpp | 2 +-
indra/newview/sgversion.cpp | 3 +
indra/newview/sgversion.h | 3 +
indra/newview/viewer_manifest.py | 1758 +++++++++++++++---------------
5 files changed, 899 insertions(+), 889 deletions(-)
diff --git a/indra/newview/fmodwrapper.cpp b/indra/newview/fmodwrapper.cpp
index d14c9134f..b544785b7 100644
--- a/indra/newview/fmodwrapper.cpp
+++ b/indra/newview/fmodwrapper.cpp
@@ -30,26 +30,30 @@
* $/LicenseInfo$
*/
+//Hack to build Darwin.
+//Need to find a better way to do this later.
+#define LL_FMOD
+
extern "C"
{
-#if LL_FMODEX
+#ifdef LL_FMODEX
void FSOUND_Sound_Init(void);
#endif
-#if LL_FMOD
+
+#ifdef LL_FMOD
void FSOUND_Init(void);
#endif
}
void* fmodwrapper(void)
-{
+{
// When building the fmodwrapper library, the linker doesn't seem to want to bring in libfmod.a unless I explicitly
// reference at least one symbol in the library. This seemed like the simplest way.
- void *ret = NULL;
-#if LL_FMODEX
- ret = (void*)&FSOUND_Sound_Init;
+#ifdef LL_FMODEX
+ return (void*)&FSOUND_Sound_Init;
#endif
-#if LL_FMOD
- ret = (void*)&FSOUND_Init;
+
+#ifdef LL_FMOD
+ return (void*)&FSOUND_Init;
#endif
- return ret;
}
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 4feeee42f..011c10cac 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -3492,7 +3492,7 @@ bool update_dialog_callback(const LLSD& notification, const LLSD& response)
LLAppViewer::sUpdaterInfo->mUpdateExePath += "\" -name \"";
LLAppViewer::sUpdaterInfo->mUpdateExePath += LLAppViewer::instance()->getSecondLifeTitle();
LLAppViewer::sUpdaterInfo->mUpdateExePath += "\" -bundleid \"";
- LLAppViewer::sUpdaterInfo->mUpdateExePath += LL_VERSION_BUNDLE_ID;
+ LLAppViewer::sUpdaterInfo->mUpdateExePath += gVersionBundleID;
LLAppViewer::sUpdaterInfo->mUpdateExePath += "\" &";
LL_DEBUGS("AppInit") << "Calling updater: " << LLAppViewer::sUpdaterInfo->mUpdateExePath << LL_ENDL;
diff --git a/indra/newview/sgversion.cpp b/indra/newview/sgversion.cpp
index 07f4c251d..615064f27 100644
--- a/indra/newview/sgversion.cpp
+++ b/indra/newview/sgversion.cpp
@@ -28,3 +28,6 @@ const S32 gVersionBuild = LL_VERSION_BUILD;
const char* gVersionChannel = LL_CHANNEL;
+#if LL_DARWIN
+const char* gVersionBundleID = LL_VERSION_BUNDLE_ID;
+#endif
\ No newline at end of file
diff --git a/indra/newview/sgversion.h b/indra/newview/sgversion.h
index 42231fc07..afdc8b51a 100644
--- a/indra/newview/sgversion.h
+++ b/indra/newview/sgversion.h
@@ -25,5 +25,8 @@ extern const S32 gVersionBuild;
extern const char* gVersionChannel;
+#if LL_DARWIN
+extern const char* gVersionBundleID;
+#endif
#endif
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index 2b11cd32b..b492ddaef 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -1,879 +1,879 @@
-#!/usr/bin/python
-# @file viewer_manifest.py
-# @author Ryan Williams
-# @brief Description of all installer viewer files, and methods for packaging
-# them into installers for all supported platforms.
-#
-# $LicenseInfo:firstyear=2006&license=viewergpl$
-#
-# Copyright (c) 2006-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 sys
-import os.path
-import re
-import tarfile
-viewer_dir = os.path.dirname(__file__)
-# add llmanifest library to our path so we don't have to muck with PYTHONPATH
-sys.path.append(os.path.join(viewer_dir, '../lib/python/indra/util'))
-from llmanifest import LLManifest, main, proper_windows_path, path_ancestors
-
-class ViewerManifest(LLManifest):
- def construct(self):
- super(ViewerManifest, self).construct()
- self.exclude("*.svn*")
- self.path(src="../../scripts/messages/message_template.msg", dst="app_settings/message_template.msg")
- self.path(src="../../etc/message.xml", dst="app_settings/message.xml")
-
- if self.prefix(src="app_settings"):
- self.exclude("logcontrol.xml")
- self.exclude("logcontrol-dev.xml")
- self.path("*.pem")
- self.path("*.ini")
- self.path("*.xml")
- self.path("*.db2")
-
- # include the entire shaders directory recursively
- self.path("shaders")
- # ... and the entire windlight directory
- self.path("windlight")
- # ... and the hunspell dictionaries
- self.path("dictionaries")
- self.end_prefix("app_settings")
-
- if self.prefix(src="character"):
- self.path("*.llm")
- self.path("*.xml")
- self.path("*.tga")
- self.end_prefix("character")
-
- # Include our fonts
- if self.prefix(src="fonts"):
- self.path("*.ttf")
- self.path("*.txt")
- self.end_prefix("fonts")
-
- # skins
- if self.prefix(src="skins"):
- self.path("paths.xml")
- # include the entire textures directory recursively
- if self.prefix(src="default/textures"):
- self.path("*.tga")
- self.path("*.j2c")
- self.path("*.jpg")
- self.path("*.png")
- self.path("textures.xml")
- self.end_prefix("default/textures")
- self.path("default/xui/*/*.xml")
- self.path("Default.xml")
- self.path("default/*.xml")
- if self.prefix(src="dark/textures"):
- self.path("*.tga")
- self.path("*.j2c")
- self.path("*.jpg")
- self.path("*.png")
- self.path("textures.xml")
- self.end_prefix("dark/textures")
- self.path("dark.xml")
- self.path("dark/*.xml")
-
- # Local HTML files (e.g. loading screen)
- if self.prefix(src="*/html"):
- self.path("*.png")
- self.path("*/*/*.html")
- self.path("*/*/*.gif")
- self.end_prefix("*/html")
- self.end_prefix("skins")
-
- # Files in the newview/ directory
- self.path("gpu_table.txt")
-
- def login_channel(self):
- """Channel reported for login and upgrade purposes ONLY;
- used for A/B testing"""
- # NOTE: Do not return the normal channel if login_channel
- # is not specified, as some code may branch depending on
- # whether or not this is present
- return self.args.get('login_channel')
-
- def buildtype(self):
- return self.args['buildtype']
- def standalone(self):
- return self.args['standalone'] == "ON"
- def grid(self):
- return self.args['grid']
- def channel(self):
- return self.args['channel']
- def channel_unique(self):
- return self.channel().replace("Second Life", "").strip()
- def channel_oneword(self):
- return "".join(self.channel_unique().split())
- def channel_lowerword(self):
- return self.channel_oneword().lower()
- def viewer_branding_id(self):
- return self.args['branding_id']
- def installer_prefix(self):
- mapping={"secondlife":'SecondLife_',
- "snowglobe":'Snowglobe_',
- "singularity":'Singularity_'}
- return mapping[self.viewer_branding_id()]
-
- def flags_list(self):
- """ Convenience function that returns the command-line flags
- for the grid"""
-
- # Set command line flags relating to the target grid
- grid_flags = ''
- if not self.default_grid():
- grid_flags = "--grid %(grid)s "\
- "--helperuri http://preview-%(grid)s.secondlife.com/helpers/" %\
- {'grid':self.grid()}
-
- # set command line flags for channel
- channel_flags = ''
- if self.login_channel() and self.login_channel() != self.channel():
- # Report a special channel during login, but use default
- channel_flags = '--channel "%s"' % (self.login_channel())
- else:
- channel_flags = '--channel "%s"' % self.channel()
-
- # Deal with settings
- if self.default_channel() and self.default_grid():
- setting_flags = ''
- elif self.default_grid():
- setting_flags = '--settings settings_%s.xml'\
- % self.channel_lowerword()
- else:
- setting_flags = '--settings settings_%s_%s.xml'\
- % (self.grid(), self.channel_lowerword())
-
- return " ".join((channel_flags, grid_flags, setting_flags)).strip()
-
-class WindowsManifest(ViewerManifest):
- def final_exe(self):
- return self.channel_oneword() + 'Viewer.exe'
-
-
- def construct(self):
- super(WindowsManifest, self).construct()
- # the final exe is complicated because we're not sure where it's coming from,
- # nor do we have a fixed name for the executable
- self.path(src='%s/secondlife-bin.exe' % self.args['configuration'], dst=self.final_exe())
-
- # Plugin host application
- self.path(os.path.join(os.pardir,
- 'llplugin', 'slplugin', self.args['configuration'], "SLPlugin.exe"),
- "SLPlugin.exe")
-
- # need to get the kdu dll from any of the build directories as well
- #~ try:
- #~ self.path(self.find_existing_file('../llkdu/%s/llkdu.dll' % self.args['configuration'],
- #~ '../../libraries/i686-win32/lib/release/llkdu.dll'),
- #~ dst='llkdu.dll')
- #~ pass
- #~ except:
- #~ print "Skipping llkdu.dll"
- #~ pass
- self.path(src="licenses-win32.txt", dst="licenses.txt")
-
- self.path("featuretable.txt")
-
- # For spellchecking
- if self.prefix(src=self.args['configuration'], dst=""):
- self.path("libhunspell.dll")
- self.end_prefix()
-
- # For use in crash reporting (generates minidumps)
- self.path("dbghelp.dll")
-
- # For using FMOD for sound... DJS
- #~if self.prefix(src="../../libraries/i686-win32/lib/release", dst=""):
- #~try:
- #~self.path("fmod.dll")
- #~pass
- #~except:
- #~print "Skipping fmod.dll - not found"
- #~ pass
- #~self.end_prefix()
-
- # For textures
- #if self.prefix(src="../../libraries/i686-win32/lib/release", dst=""):
- # self.path("openjpeg.dll")
- # self.end_prefix()
-
- # Plugins - FilePicker
- if self.prefix(src='../plugins/filepicker/%s' % self.args['configuration'], dst="llplugin"):
- self.path("basic_plugin_filepicker.dll")
- self.end_prefix()
-
- # Media plugins - QuickTime
- if self.prefix(src='../plugins/quicktime/%s' % self.args['configuration'], dst="llplugin"):
- self.path("media_plugin_quicktime.dll")
- self.end_prefix()
-
- # Media plugins - WebKit/Qt
- if self.prefix(src='../plugins/webkit/%s' % self.args['configuration'], dst="llplugin"):
- self.path("media_plugin_webkit.dll")
- self.end_prefix()
-
- # For WebKit/Qt plugin runtimes
- if self.prefix(src="../../libraries/i686-win32/lib/release", dst="llplugin"):
- self.path("libeay32.dll")
- self.path("qtcore4.dll")
- self.path("qtgui4.dll")
- self.path("qtnetwork4.dll")
- self.path("qtopengl4.dll")
- self.path("qtwebkit4.dll")
- self.path("qtxmlpatterns4.dll")
- self.path("ssleay32.dll")
- self.end_prefix()
-
- # For WebKit/Qt plugin runtimes (image format plugins)
- if self.prefix(src="../../libraries/i686-win32/lib/release/imageformats", dst="llplugin/imageformats"):
- self.path("qgif4.dll")
- self.path("qico4.dll")
- self.path("qjpeg4.dll")
- self.path("qmng4.dll")
- self.path("qsvg4.dll")
- self.path("qtiff4.dll")
- self.end_prefix()
-
- if self.prefix(src="../../libraries/i686-win32/lib/release/codecs", dst="llplugin/codecs"):
- self.path("qcncodecs4.dll")
- self.path("qjpcodecs4.dll")
- self.path("qkrcodecs4.dll")
- self.path("qtwcodecs4.dll")
- self.end_prefix()
-
- # Get llcommon and deps. If missing assume static linkage and continue.
- if self.prefix(src=self.args['configuration'], dst=""):
- try:
- self.path('llcommon.dll')
- except RuntimeError, err:
- print err.message
- print "Skipping llcommon.dll (assuming llcommon was linked statically)"
- self.end_prefix()
- if self.prefix(src="../../libraries/i686-win32/lib/release", dst=""):
- try:
- self.path('libapr-1.dll')
- self.path('libaprutil-1.dll')
- self.path('libapriconv-1.dll')
- except RuntimeError, err:
- pass
- self.end_prefix()
-
- # For google-perftools tcmalloc allocator.
- self.path("../../libraries/i686-win32/lib/release/libtcmalloc_minimal.dll", dst="libtcmalloc_minimal.dll")
-
- try:
- if self.prefix("../../libraries/i686-win32/lib/release/msvcrt", dst=""):
- self.path("*.dll")
- self.path("*.manifest")
- self.end_prefix()
- except:
- pass
-
-
- # These need to be installed as a SxS assembly, currently a 'private' assembly.
- # See http://msdn.microsoft.com/en-us/library/ms235291(VS.80).aspx
- #~ if self.prefix(src=self.args['configuration'], dst=""):
- #~ if self.args['configuration'] == 'Debug':
- #~ self.path("msvcr80d.dll")
- #~ self.path("msvcp80d.dll")
- #~ self.path("Microsoft.VC80.DebugCRT.manifest")
- #~ else:
- #~ self.path("msvcr80.dll")
- #~ self.path("msvcp80.dll")
- #~ self.path("Microsoft.VC80.CRT.manifest")
- #~ self.end_prefix()
-
- # The config file name needs to match the exe's name.
- #~ self.path(src="%s/secondlife-bin.exe.config" % self.args['configuration'], dst=self.final_exe() + ".config")
-
- # Vivox runtimes
- if self.prefix(src="vivox-runtime/i686-win32", dst=""):
- self.path("SLVoice.exe")
- self.path("alut.dll")
- self.path("vivoxsdk.dll")
- self.path("ortp.dll")
- self.path("wrap_oal.dll")
- self.end_prefix()
-
- if self.args['extra_libraries'] != None:
- print self.args['extra_libraries']
- path_list = self.args['extra_libraries'].split('|')
- for path in path_list:
- path_pair = path.rsplit('/', 1)
- if self.prefix(src=path_pair[0], dst=""):
- self.path(path_pair[1])
- self.end_prefix()
-
- # pull in the crash logger and updater from other projects
- self.path(src='../win_crash_logger/%s/windows-crash-logger.exe' % self.args['configuration'], dst="win_crash_logger.exe")
- self.path(src='../win_updater/%s/windows-updater.exe' % self.args['configuration'], dst="updater.exe")
-
-
- def nsi_file_commands(self, install=True):
- def wpath(path):
- if path.endswith('/') or path.endswith(os.path.sep):
- path = path[:-1]
- path = path.replace('/', '\\')
- return path
-
- result = ""
- dest_files = [pair[1] for pair in self.file_list if pair[0] and os.path.isfile(pair[1])]
- # sort deepest hierarchy first
- dest_files.sort(lambda a,b: cmp(a.count(os.path.sep),b.count(os.path.sep)) or cmp(a,b))
- dest_files.reverse()
- out_path = None
- for pkg_file in dest_files:
- rel_file = os.path.normpath(pkg_file.replace(self.get_dst_prefix()+os.path.sep,''))
- installed_dir = wpath(os.path.join('$INSTDIR', os.path.dirname(rel_file)))
- pkg_file = wpath(os.path.normpath(pkg_file))
- if installed_dir != out_path:
- if install:
- out_path = installed_dir
- result += 'SetOutPath ' + out_path + '\n'
- if install:
- result += 'File ' + pkg_file + '\n'
- else:
- result += 'Delete ' + wpath(os.path.join('$INSTDIR', rel_file)) + '\n'
- # at the end of a delete, just rmdir all the directories
- if not install:
- deleted_file_dirs = [os.path.dirname(pair[1].replace(self.get_dst_prefix()+os.path.sep,'')) for pair in self.file_list]
- # find all ancestors so that we don't skip any dirs that happened to have no non-dir children
- deleted_dirs = []
- for d in deleted_file_dirs:
- deleted_dirs.extend(path_ancestors(d))
- # sort deepest hierarchy first
- deleted_dirs.sort(lambda a,b: cmp(a.count(os.path.sep),b.count(os.path.sep)) or cmp(a,b))
- deleted_dirs.reverse()
- prev = None
- for d in deleted_dirs:
- if d != prev: # skip duplicates
- result += 'RMDir ' + wpath(os.path.join('$INSTDIR', os.path.normpath(d))) + '\n'
- prev = d
-
- return result
-
- def package_finish(self):
- # a standard map of strings for replacing in the templates
- substitution_strings = {
- 'version' : '.'.join(self.args['version']),
- 'version_short' : '.'.join(self.args['version'][:-1]),
- 'version_dashes' : '-'.join(self.args['version']),
- 'final_exe' : self.final_exe(),
- 'grid':self.args['grid'],
- 'grid_caps':self.args['grid'].upper(),
- # escape quotes becase NSIS doesn't handle them well
- 'flags':self.flags_list().replace('"', '$\\"'),
- 'channel':self.channel(),
- 'channel_oneword':self.channel_oneword(),
- 'channel_unique':self.channel_unique(),
- }
-
- version_vars = """
- !define INSTEXE "%(final_exe)s"
- !define VERSION "%(version_short)s"
- !define VERSION_LONG "%(version)s"
- !define VERSION_DASHES "%(version_dashes)s"
- """ % substitution_strings
- installer_file = "%(channel_oneword)s_%(version_dashes)s_Setup.exe"
- grid_vars_template = """
- OutFile "%(installer_file)s"
- !define VIEWERNAME "%(channel)s"
- !define INSTFLAGS "%(flags)s"
- !define INSTNAME "%(channel_oneword)s"
- !define SHORTCUT "%(channel)s Viewer"
- !define URLNAME "secondlife"
- !define INSTALL_ICON "install_icon_singularity.ico"
- !define UNINSTALL_ICON "install_icon_singularity.ico"
- Caption "${VIEWERNAME} ${VERSION_LONG}"
- """
- if 'installer_name' in self.args:
- installer_file = self.args['installer_name']
- else:
- installer_file = installer_file % substitution_strings
- substitution_strings['installer_file'] = installer_file
-
- tempfile = "secondlife_setup_tmp.nsi"
- # the following replaces strings in the nsi template
- # it also does python-style % substitution
- self.replace_in("installers/windows/installer_template.nsi", tempfile, {
- "%%VERSION%%":version_vars,
- "%%SOURCE%%":self.get_src_prefix(),
- "%%GRID_VARS%%":grid_vars_template % substitution_strings,
- "%%INSTALL_FILES%%":self.nsi_file_commands(True),
- "%%DELETE_FILES%%":self.nsi_file_commands(False)})
-
- # We use the Unicode version of NSIS, available from
- # http://www.scratchpaper.com/
- try:
- import _winreg as reg
- NSIS_path = reg.QueryValue(reg.HKEY_LOCAL_MACHINE, r"SOFTWARE\NSIS\Unicode") + '\\makensis.exe'
- self.run_command('"' + proper_windows_path(NSIS_path) + '" ' + self.dst_path_of(tempfile))
- except:
- try:
- NSIS_path = os.environ['ProgramFiles'] + '\\NSIS\\Unicode\\makensis.exe'
- self.run_command('"' + proper_windows_path(NSIS_path) + '" ' + self.dst_path_of(tempfile))
- except:
- NSIS_path = os.environ['ProgramFiles(X86)'] + '\\NSIS\\Unicode\\makensis.exe'
- self.run_command('"' + proper_windows_path(NSIS_path) + '" ' + self.dst_path_of(tempfile))
- # self.remove(self.dst_path_of(tempfile))
- # If we're on a build machine, sign the code using our Authenticode certificate. JC
- sign_py = os.path.expandvars("{SIGN_PY}")
- if sign_py == "" or sign_py == "{SIGN_PY}":
- sign_py = 'C:\\buildscripts\\code-signing\\sign.py'
- if os.path.exists(sign_py):
- self.run_command('python ' + sign_py + ' ' + self.dst_path_of(installer_file))
- else:
- print "Skipping code signing,", sign_py, "does not exist"
- self.created_path(self.dst_path_of(installer_file))
- self.package_file = installer_file
-
-
-class DarwinManifest(ViewerManifest):
- def construct(self):
- # copy over the build result (this is a no-op if run within the xcode script)
- self.path(self.args['configuration'] + "/" + self.app_name() + ".app", dst="")
-
- if self.prefix(src="", dst="Contents"): # everything goes in Contents
- self.path(self.info_plist_name(), dst="Info.plist")
-
- # copy additional libs in /Contents/MacOS/
- self.path("../../libraries/universal-darwin/lib_release/libhunspell-1.2.dylib", dst="MacOS/libhunspell-1.2.dylib")
- self.path("../../libraries/universal-darwin/lib_release/libndofdev.dylib", dst="MacOS/libndofdev.dylib")
- #self.path("../../libraries/universal-darwin/lib_release/libvorbisenc.2.dylib", dst="MacOS/libvorbisenc.2.dylib")
- #self.path("../../libraries/universal-darwin/lib_release/libvorbisfile.3.dylib", dst="MacOS/libvorbisfile.3.dylib")
- #self.path("../../libraries/universal-darwin/lib_release/libvorbis.0.dylib", dst="MacOS/libvorbis.0.dylib")
- #self.path("../../libraries/universal-darwin/lib_release/libogg.0.dylib", dst="MacOS/libogg.0.dylib")
-
- # most everything goes in the Resources directory
- if self.prefix(src="", dst="Resources"):
- super(DarwinManifest, self).construct()
-
- if self.prefix("cursors_mac"):
- self.path("*.tif")
- self.end_prefix("cursors_mac")
-
- self.path("licenses-mac.txt", dst="licenses.txt")
- self.path("featuretable_mac.txt")
- self.path("SecondLife.nib")
-
- # SG:TODO
- self.path("../newview/res/singularity.icns", dst="singularity.icns")
-
- # Translations
- self.path("English.lproj")
- self.path("German.lproj")
- self.path("Japanese.lproj")
- self.path("Korean.lproj")
- self.path("da.lproj")
- self.path("es.lproj")
- self.path("fr.lproj")
- self.path("hu.lproj")
- self.path("it.lproj")
- self.path("nl.lproj")
- self.path("pl.lproj")
- self.path("pt.lproj")
- self.path("ru.lproj")
- self.path("tr.lproj")
- self.path("uk.lproj")
- self.path("zh-Hans.lproj")
-
- # SLVoice and vivox lols
- self.path("vivox-runtime/universal-darwin/libalut.dylib", "libalut.dylib")
- self.path("vivox-runtime/universal-darwin/libopenal.dylib", "libopenal.dylib")
- self.path("vivox-runtime/universal-darwin/libortp.dylib", "libortp.dylib")
- self.path("vivox-runtime/universal-darwin/libvivoxsdk.dylib", "libvivoxsdk.dylib")
- self.path("vivox-runtime/universal-darwin/SLVoice", "SLVoice")
-
- self.path("../llcommon/" + self.args['configuration'] + "/libllcommon.dylib", "libllcommon.dylib")
-
- libfile = "lib%s.dylib"
- libdir = "../../libraries/universal-darwin/lib_release"
-
- for libfile in ("libapr-1.0.3.7.dylib",
- "libaprutil-1.0.3.8.dylib",
- "libexpat.0.5.0.dylib"):
- self.path(os.path.join(libdir, libfile), libfile)
-
- # For using FMOD for sound...but, fmod is proprietary so some might not use it...
- try:
- self.path(self.args['configuration'] + "/libfmodwrapper.dylib", "libfmodwrapper.dylib")
- pass
- except:
- print "Skipping libfmodwrapper.dylib - not found"
- pass
-
- # our apps
- try:
- self.path("../mac_crash_logger/" + self.args['configuration'] + "/mac-crash-logger.app", "mac-crash-logger.app")
- self.path("../mac_updater/" + self.args['configuration'] + "/mac-updater.app", "mac-updater.app")
- except:
- pass
-
- # plugin launcher
- self.path("../llplugin/slplugin/" + self.args['configuration'] + "/SLPlugin.app", "SLPlugin.app")
-
- # dependencies on shared libs
- mac_crash_logger_res_path = self.dst_path_of("mac-crash-logger.app/Contents/Resources")
- slplugin_res_path = self.dst_path_of("SLPlugin.app/Contents/Resources")
- for libfile in ("libllcommon.dylib",
- "libapr-1.0.3.7.dylib",
- "libaprutil-1.0.3.8.dylib",
- "libexpat.0.5.0.dylib"):
- target_lib = os.path.join('../../..', libfile)
- self.run_command("ln -sf %(target)r %(link)r" %
- {'target': target_lib,
- 'link' : os.path.join(slplugin_res_path, libfile)}
- )
- #self.run_command("ln -sf %(target)r %(link)r" %
- # {'target': target_lib,
- # 'link' : os.path.join(mac_crash_logger_res_path, libfile)}
- # )
-
- # plugins
- if self.prefix(src="", dst="llplugin"):
- self.path("../plugins/filepicker/" + self.args['configuration'] + "/basic_plugin_filepicker.dylib", "basic_plugin_filepicker.dylib")
- self.path("../plugins/quicktime/" + self.args['configuration'] + "/media_plugin_quicktime.dylib", "media_plugin_quicktime.dylib")
- self.path("../plugins/webkit/" + self.args['configuration'] + "/media_plugin_webkit.dylib", "media_plugin_webkit.dylib")
- self.path("../../libraries/universal-darwin/lib_release/libllqtwebkit.dylib", "libllqtwebkit.dylib")
-
- self.end_prefix("llplugin")
-
- # command line arguments for connecting to the proper grid
- self.put_in_file(self.flags_list(), 'arguments.txt')
-
- self.end_prefix("Resources")
-
- self.end_prefix("Contents")
-
- # NOTE: the -S argument to strip causes it to keep enough info for
- # annotated backtraces (i.e. function names in the crash log). 'strip' with no
- # arguments yields a slightly smaller binary but makes crash logs mostly useless.
- # This may be desirable for the final release. Or not.
- if self.buildtype().lower()=='release':
- if ("package" in self.args['actions'] or
- "unpacked" in self.args['actions']):
- self.run_command('strip -S "%(viewer_binary)s"' %
- { 'viewer_binary' : self.dst_path_of('Contents/MacOS/'+self.app_name())})
-
- def app_name(self):
- return "Singularity"
-
- def info_plist_name(self):
- return "Info-Singularity.plist"
-
- def package_finish(self):
- channel_standin = self.app_name()
- if not self.default_channel_for_brand():
- channel_standin = self.channel()
-
- imagename=self.installer_prefix() + '_'.join(self.args['version'])
-
- # See Ambroff's Hack comment further down if you want to create new bundles and dmg
- volname=self.app_name() + " Installer" # DO NOT CHANGE without checking Ambroff's Hack comment further down
-
- if self.default_channel_for_brand():
- if not self.default_grid():
- # beta case
- imagename = imagename + '_' + self.args['grid'].upper()
- else:
- # first look, etc
- imagename = imagename + '_' + self.channel_oneword().upper()
-
- sparsename = imagename + ".sparseimage"
- finalname = imagename + ".dmg"
- # make sure we don't have stale files laying about
- self.remove(sparsename, finalname)
-
- self.run_command('hdiutil create "%(sparse)s" -volname "%(vol)s" -fs HFS+ -type SPARSE -megabytes 700 -layout SPUD' % {
- 'sparse':sparsename,
- 'vol':volname})
-
- # mount the image and get the name of the mount point and device node
- hdi_output = self.run_command('hdiutil attach -private "' + sparsename + '"')
- devfile = re.search("/dev/disk([0-9]+)[^s]", hdi_output).group(0).strip()
- volpath = re.search('HFS\s+(.+)', hdi_output).group(1).strip()
-
- # Copy everything in to the mounted .dmg
-
- if self.default_channel_for_brand() and not self.default_grid():
- app_name = self.app_name() + " " + self.args['grid']
- else:
- app_name = channel_standin.strip()
-
- # Hack:
- # Because there is no easy way to coerce the Finder into positioning
- # the app bundle in the same place with different app names, we are
- # adding multiple .DS_Store files to svn. There is one for release,
- # one for release candidate and one for first look. Any other channels
- # will use the release .DS_Store, and will look broken.
- # - Ambroff 2008-08-20
- # Added a .DS_Store for snowglobe - Merov 2009-06-17
-
- # We have a single branded installer for all snowglobe channels so snowglobe logic is a bit different
- if (self.app_name()=="Snowglobe"):
- dmg_template = os.path.join ('installers', 'darwin', 'snowglobe-dmg')
- else:
- dmg_template = os.path.join(
- 'installers',
- 'darwin',
- '%s-dmg' % "".join(self.channel_unique().split()).lower())
-
- if not os.path.exists (self.src_path_of(dmg_template)):
- dmg_template = os.path.join ('installers', 'darwin', 'release-dmg')
-
- for s,d in {self.get_dst_prefix():app_name + ".app",
- os.path.join(dmg_template, "_VolumeIcon.icns"): ".VolumeIcon.icns",
- os.path.join(dmg_template, "background.jpg"): "background.jpg",
- os.path.join(dmg_template, "_DS_Store"): ".DS_Store"}.items():
- print "Copying to dmg", s, d
- self.copy_action(self.src_path_of(s), os.path.join(volpath, d))
-
- # Hide the background image, DS_Store file, and volume icon file (set their "visible" bit)
- self.run_command('SetFile -a V "' + os.path.join(volpath, ".VolumeIcon.icns") + '"')
- self.run_command('SetFile -a V "' + os.path.join(volpath, "background.jpg") + '"')
- self.run_command('SetFile -a V "' + os.path.join(volpath, ".DS_Store") + '"')
-
- # Create the alias file (which is a resource file) from the .r
- self.run_command('rez "' + self.src_path_of("installers/darwin/release-dmg/Applications-alias.r") + '" -o "' + os.path.join(volpath, "Applications") + '"')
-
- # Set the alias file's alias and custom icon bits
- self.run_command('SetFile -a AC "' + os.path.join(volpath, "Applications") + '"')
-
- # Set the disk image root's custom icon bit
- self.run_command('SetFile -a C "' + volpath + '"')
-
- # Unmount the image
- self.run_command('hdiutil detach -force "' + devfile + '"')
-
- print "Converting temp disk image to final disk image"
- self.run_command('hdiutil convert "%(sparse)s" -format UDZO -imagekey zlib-level=9 -o "%(final)s"' % {'sparse':sparsename, 'final':finalname})
- # get rid of the temp file
- self.package_file = finalname
- self.remove(sparsename)
-
-class LinuxManifest(ViewerManifest):
- def construct(self):
- super(LinuxManifest, self).construct()
- self.path("licenses-linux.txt","licenses.txt")
-
- self.path("res/"+self.icon_name(),self.icon_name())
- if self.prefix("linux_tools", dst=""):
- self.path("client-readme.txt","README-linux.txt")
- self.path("client-readme-voice.txt","README-linux-voice.txt")
- self.path("client-readme-joystick.txt","README-linux-joystick.txt")
- self.path("wrapper.sh",self.wrapper_name())
- self.path("handle_secondlifeprotocol.sh")
- self.path("register_secondlifeprotocol.sh")
- self.end_prefix("linux_tools")
-
- # Create an appropriate gridargs.dat for this package, denoting required grid.
- self.put_in_file(self.flags_list(), 'gridargs.dat')
-
- if self.buildtype().lower()=='release':
- self.path("secondlife-stripped","bin/"+self.binary_name())
- self.path("../linux_crash_logger/linux-crash-logger-stripped","linux-crash-logger.bin")
- else:
- self.path("secondlife-bin","bin/"+self.binary_name())
- self.path("../linux_crash_logger/linux-crash-logger","linux-crash-logger.bin")
-
- self.path("linux_tools/launch_url.sh","launch_url.sh")
- self.path("../llplugin/slplugin/SLPlugin", "bin/SLPlugin")
- if self.prefix("res-sdl"):
- self.path("*")
- # recurse
- self.end_prefix("res-sdl")
-
- # plugins
- if self.prefix(src="", dst="bin/llplugin"):
- self.path("../plugins/filepicker/libbasic_plugin_filepicker.so", "libbasic_plugin_filepicker.so")
- self.path("../plugins/webkit/libmedia_plugin_webkit.so", "libmedia_plugin_webkit.so")
- self.path("../plugins/gstreamer010/libmedia_plugin_gstreamer010.so", "libmedia_plugin_gstreamer.so")
- self.end_prefix("bin/llplugin")
-
- self.path("featuretable_linux.txt")
-
- def wrapper_name(self):
- return 'singularity'
-
- def binary_name(self):
- return 'singularity-do-not-run-directly'
-
- def icon_name(self):
- return "singularity_icon.png"
-
- def package_finish(self):
- if 'installer_name' in self.args:
- installer_name = self.args['installer_name']
- else:
- installer_name_components = [self.installer_prefix(), self.args.get('arch')]
- installer_name_components.extend(self.args['version'])
- installer_name = "_".join(installer_name_components)
- if self.default_channel():
- if not self.default_grid():
- installer_name += '_' + self.args['grid'].upper()
- else:
- installer_name += '_' + self.channel_oneword().upper()
-
- if self.args['buildtype'].lower() in ['release', 'releasesse2']:
- print "* Going strip-crazy on the packaged binaries, since this is a RELEASE build"
- # makes some small assumptions about our packaged dir structure
- self.run_command("find %(d)r/bin %(d)r/lib* -type f | xargs --no-run-if-empty strip --strip-unneeded" % {'d': self.get_dst_prefix()} )
- self.run_command("find %(d)r/bin %(d)r/lib* -type f -not -name \\*.so | xargs --no-run-if-empty strip -s" % {'d': self.get_dst_prefix()} )
-
- # Fix access permissions
- self.run_command("""
- find '%(dst)s' -type d -print0 | xargs -0 --no-run-if-empty chmod 755;
- find '%(dst)s' -type f -perm 0700 -print0 | xargs -0 --no-run-if-empty chmod 0755;
- find '%(dst)s' -type f -perm 0500 -print0 | xargs -0 --no-run-if-empty chmod 0555;
- find '%(dst)s' -type f -perm 0600 -print0 | xargs -0 --no-run-if-empty chmod 0644;
- find '%(dst)s' -type f -perm 0400 -print0 | xargs -0 --no-run-if-empty chmod 0444;
- true""" % {'dst':self.get_dst_prefix() })
- self.package_file = installer_name + '.tar.bz2'
-
- # temporarily move directory tree so that it has the right
- # name in the tarfile
- self.run_command("mv '%(dst)s' '%(inst)s'" % {
- 'dst': self.get_dst_prefix(),
- 'inst': self.build_path_of(installer_name)})
- try:
- # --numeric-owner hides the username of the builder for
- # security etc.
- # I'm leaving this disabled for speed
- #self.run_command("tar -C '%(dir)s' --numeric-owner -cjf "
- # "'%(inst_path)s.tar.bz2' %(inst_name)s" % {
- # 'dir': self.get_build_prefix(),
- # 'inst_name': installer_name,
- # 'inst_path':self.build_path_of(installer_name)})
- print ''
- finally:
- self.run_command("mv '%(inst)s' '%(dst)s'" % {
- 'dst': self.get_dst_prefix(),
- 'inst': self.build_path_of(installer_name)})
-
-
-class Linux_i686Manifest(LinuxManifest):
- def construct(self):
- super(Linux_i686Manifest, self).construct()
-
- self.path("../llcommon/libllcommon.so", "lib/libllcommon.so")
-
- if (not self.standalone()) and self.prefix("../../libraries/i686-linux/lib_release_client", dst="lib"):
-
- try:
- self.path("libkdu_v42R.so", "libkdu.so")
- pass
- except:
- print "Skipping libkdu_v42R.so - not found"
- pass
-
- try:
- self.path("libfmod-3.75.so")
- pass
- except:
- print "Skipping libfmod-3.75.so - not found"
- pass
-
- self.path("libapr-1.so.0")
- self.path("libaprutil-1.so.0")
- self.path("libdb-4.2.so")
- self.path("libcrypto.so.0.9.7")
- self.path("libexpat.so.1")
- self.path("libhunspell-1.2.so.0.0.0", "libhunspell-1.2.so.0")
- self.path("libssl.so.0.9.7")
- #self.path("libuuid.so.1")
- self.path("libSDL-1.2.so.0")
- self.path("libELFIO.so")
- #self.path("libopenjpeg.so.1.3.0", "libopenjpeg.so.1.3")
- self.path("libalut.so")
- self.path("libopenal.so.1")
- self.path("libtcmalloc_minimal.so.0")
- self.path("libtcmalloc_minimal.so.0.2.2")
- self.end_prefix("lib")
-
-
- # Vivox runtimes
- if self.prefix(src="vivox-runtime/i686-linux", dst="bin"):
- self.path("SLVoice")
- self.end_prefix()
- if self.prefix(src="vivox-runtime/i686-linux", dst="lib"):
- self.path("libortp.so")
- self.path("libvivoxsdk.so")
- self.end_prefix("lib")
-
-
-class Linux_x86_64Manifest(LinuxManifest):
- def construct(self):
- super(Linux_x86_64Manifest, self).construct()
-
- self.path("../llcommon/libllcommon.so", "lib64/libllcommon.so")
-
- if (not self.standalone()) and self.prefix("../../libraries/x86_64-linux/lib_release_client", dst="lib64"):
- self.path("libapr-1.so.0")
- self.path("libaprutil-1.so.0")
- self.path("libdb-4.2.so")
- self.path("libcrypto.so.0.9.8")
- self.path("libexpat.so.1")
- self.path("libhunspell-1.2.so.0.0.0", "libhunspell-1.2.so.0")
- self.path("libssl.so.0.9.8")
- self.path("libuuid.so", "libuuid.so.1")
- self.path("libSDL-1.2.so.0")
- self.path("libELFIO.so")
- self.path("libjpeg.so.7")
- self.path("libpng12.so.0")
- self.path("libopenjpeg.so.2")
- self.path("libxml2.so.2")
- #self.path("libz.so.1") #not needed
-
- # OpenAL
- self.path("libopenal.so.1")
- self.path("libalut.so.0")
-
- self.end_prefix("lib64")
-
- # Vivox runtimes and libs
- if self.prefix(src="vivox-runtime/i686-linux", dst="bin"):
- self.path("SLVoice")
- self.end_prefix("bin")
-
- if self.prefix(src="vivox-runtime/i686-linux", dst="lib32"):
- #self.path("libalut.so")
- self.path("libortp.so")
- self.path("libvivoxsdk.so")
- self.end_prefix("lib32")
-
- # 32bit libs needed for voice
- if self.prefix("../../libraries/x86_64-linux/lib_release_client/32bit-compat", dst="lib32"):
- self.path("libalut.so")
- self.path("libidn.so.11")
- self.path("libopenal.so.1")
- # self.path("libortp.so")
- self.path("libuuid.so.1")
- self.end_prefix("lib32")
-
-if __name__ == "__main__":
- main()
+#!/usr/bin/python
+# @file viewer_manifest.py
+# @author Ryan Williams
+# @brief Description of all installer viewer files, and methods for packaging
+# them into installers for all supported platforms.
+#
+# $LicenseInfo:firstyear=2006&license=viewergpl$
+#
+# Copyright (c) 2006-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 sys
+import os.path
+import re
+import tarfile
+viewer_dir = os.path.dirname(__file__)
+# add llmanifest library to our path so we don't have to muck with PYTHONPATH
+sys.path.append(os.path.join(viewer_dir, '../lib/python/indra/util'))
+from llmanifest import LLManifest, main, proper_windows_path, path_ancestors
+
+class ViewerManifest(LLManifest):
+ def construct(self):
+ super(ViewerManifest, self).construct()
+ self.exclude("*.svn*")
+ self.path(src="../../scripts/messages/message_template.msg", dst="app_settings/message_template.msg")
+ self.path(src="../../etc/message.xml", dst="app_settings/message.xml")
+
+ if self.prefix(src="app_settings"):
+ self.exclude("logcontrol.xml")
+ self.exclude("logcontrol-dev.xml")
+ self.path("*.pem")
+ self.path("*.ini")
+ self.path("*.xml")
+ self.path("*.db2")
+
+ # include the entire shaders directory recursively
+ self.path("shaders")
+ # ... and the entire windlight directory
+ self.path("windlight")
+ # ... and the hunspell dictionaries
+ self.path("dictionaries")
+ self.end_prefix("app_settings")
+
+ if self.prefix(src="character"):
+ self.path("*.llm")
+ self.path("*.xml")
+ self.path("*.tga")
+ self.end_prefix("character")
+
+ # Include our fonts
+ if self.prefix(src="fonts"):
+ self.path("*.ttf")
+ self.path("*.txt")
+ self.end_prefix("fonts")
+
+ # skins
+ if self.prefix(src="skins"):
+ self.path("paths.xml")
+ # include the entire textures directory recursively
+ if self.prefix(src="default/textures"):
+ self.path("*.tga")
+ self.path("*.j2c")
+ self.path("*.jpg")
+ self.path("*.png")
+ self.path("textures.xml")
+ self.end_prefix("default/textures")
+ self.path("default/xui/*/*.xml")
+ self.path("Default.xml")
+ self.path("default/*.xml")
+ if self.prefix(src="dark/textures"):
+ self.path("*.tga")
+ self.path("*.j2c")
+ self.path("*.jpg")
+ self.path("*.png")
+ self.path("textures.xml")
+ self.end_prefix("dark/textures")
+ self.path("dark.xml")
+ self.path("dark/*.xml")
+
+ # Local HTML files (e.g. loading screen)
+ if self.prefix(src="*/html"):
+ self.path("*.png")
+ self.path("*/*/*.html")
+ self.path("*/*/*.gif")
+ self.end_prefix("*/html")
+ self.end_prefix("skins")
+
+ # Files in the newview/ directory
+ self.path("gpu_table.txt")
+
+ def login_channel(self):
+ """Channel reported for login and upgrade purposes ONLY;
+ used for A/B testing"""
+ # NOTE: Do not return the normal channel if login_channel
+ # is not specified, as some code may branch depending on
+ # whether or not this is present
+ return self.args.get('login_channel')
+
+ def buildtype(self):
+ return self.args['buildtype']
+ def standalone(self):
+ return self.args['standalone'] == "ON"
+ def grid(self):
+ return self.args['grid']
+ def channel(self):
+ return self.args['channel']
+ def channel_unique(self):
+ return self.channel().replace("Second Life", "").strip()
+ def channel_oneword(self):
+ return "".join(self.channel_unique().split())
+ def channel_lowerword(self):
+ return self.channel_oneword().lower()
+ def viewer_branding_id(self):
+ return self.args['branding_id']
+ def installer_prefix(self):
+ mapping={"secondlife":'SecondLife_',
+ "snowglobe":'Snowglobe_',
+ "singularity":'Singularity_'}
+ return mapping[self.viewer_branding_id()]
+
+ def flags_list(self):
+ """ Convenience function that returns the command-line flags
+ for the grid"""
+
+ # Set command line flags relating to the target grid
+ grid_flags = ''
+ if not self.default_grid():
+ grid_flags = "--grid %(grid)s "\
+ "--helperuri http://preview-%(grid)s.secondlife.com/helpers/" %\
+ {'grid':self.grid()}
+
+ # set command line flags for channel
+ channel_flags = ''
+ if self.login_channel() and self.login_channel() != self.channel():
+ # Report a special channel during login, but use default
+ channel_flags = '--channel "%s"' % (self.login_channel())
+ else:
+ channel_flags = '--channel "%s"' % self.channel()
+
+ # Deal with settings
+ if self.default_channel() and self.default_grid():
+ setting_flags = ''
+ elif self.default_grid():
+ setting_flags = '--settings settings_%s.xml'\
+ % self.channel_lowerword()
+ else:
+ setting_flags = '--settings settings_%s_%s.xml'\
+ % (self.grid(), self.channel_lowerword())
+
+ return " ".join((channel_flags, grid_flags, setting_flags)).strip()
+
+class WindowsManifest(ViewerManifest):
+ def final_exe(self):
+ return self.channel_oneword() + 'Viewer.exe'
+
+
+ def construct(self):
+ super(WindowsManifest, self).construct()
+ # the final exe is complicated because we're not sure where it's coming from,
+ # nor do we have a fixed name for the executable
+ self.path(src='%s/secondlife-bin.exe' % self.args['configuration'], dst=self.final_exe())
+
+ # Plugin host application
+ self.path(os.path.join(os.pardir,
+ 'llplugin', 'slplugin', self.args['configuration'], "SLPlugin.exe"),
+ "SLPlugin.exe")
+
+ # need to get the kdu dll from any of the build directories as well
+ #~ try:
+ #~ self.path(self.find_existing_file('../llkdu/%s/llkdu.dll' % self.args['configuration'],
+ #~ '../../libraries/i686-win32/lib/release/llkdu.dll'),
+ #~ dst='llkdu.dll')
+ #~ pass
+ #~ except:
+ #~ print "Skipping llkdu.dll"
+ #~ pass
+ self.path(src="licenses-win32.txt", dst="licenses.txt")
+
+ self.path("featuretable.txt")
+
+ # For spellchecking
+ if self.prefix(src=self.args['configuration'], dst=""):
+ self.path("libhunspell.dll")
+ self.end_prefix()
+
+ # For use in crash reporting (generates minidumps)
+ self.path("dbghelp.dll")
+
+ # For using FMOD for sound... DJS
+ #~if self.prefix(src="../../libraries/i686-win32/lib/release", dst=""):
+ #~try:
+ #~self.path("fmod.dll")
+ #~pass
+ #~except:
+ #~print "Skipping fmod.dll - not found"
+ #~ pass
+ #~self.end_prefix()
+
+ # For textures
+ #if self.prefix(src="../../libraries/i686-win32/lib/release", dst=""):
+ # self.path("openjpeg.dll")
+ # self.end_prefix()
+
+ # Plugins - FilePicker
+ if self.prefix(src='../plugins/filepicker/%s' % self.args['configuration'], dst="llplugin"):
+ self.path("basic_plugin_filepicker.dll")
+ self.end_prefix()
+
+ # Media plugins - QuickTime
+ if self.prefix(src='../plugins/quicktime/%s' % self.args['configuration'], dst="llplugin"):
+ self.path("media_plugin_quicktime.dll")
+ self.end_prefix()
+
+ # Media plugins - WebKit/Qt
+ if self.prefix(src='../plugins/webkit/%s' % self.args['configuration'], dst="llplugin"):
+ self.path("media_plugin_webkit.dll")
+ self.end_prefix()
+
+ # For WebKit/Qt plugin runtimes
+ if self.prefix(src="../../libraries/i686-win32/lib/release", dst="llplugin"):
+ self.path("libeay32.dll")
+ self.path("qtcore4.dll")
+ self.path("qtgui4.dll")
+ self.path("qtnetwork4.dll")
+ self.path("qtopengl4.dll")
+ self.path("qtwebkit4.dll")
+ self.path("qtxmlpatterns4.dll")
+ self.path("ssleay32.dll")
+ self.end_prefix()
+
+ # For WebKit/Qt plugin runtimes (image format plugins)
+ if self.prefix(src="../../libraries/i686-win32/lib/release/imageformats", dst="llplugin/imageformats"):
+ self.path("qgif4.dll")
+ self.path("qico4.dll")
+ self.path("qjpeg4.dll")
+ self.path("qmng4.dll")
+ self.path("qsvg4.dll")
+ self.path("qtiff4.dll")
+ self.end_prefix()
+
+ if self.prefix(src="../../libraries/i686-win32/lib/release/codecs", dst="llplugin/codecs"):
+ self.path("qcncodecs4.dll")
+ self.path("qjpcodecs4.dll")
+ self.path("qkrcodecs4.dll")
+ self.path("qtwcodecs4.dll")
+ self.end_prefix()
+
+ # Get llcommon and deps. If missing assume static linkage and continue.
+ if self.prefix(src=self.args['configuration'], dst=""):
+ try:
+ self.path('llcommon.dll')
+ except RuntimeError, err:
+ print err.message
+ print "Skipping llcommon.dll (assuming llcommon was linked statically)"
+ self.end_prefix()
+ if self.prefix(src="../../libraries/i686-win32/lib/release", dst=""):
+ try:
+ self.path('libapr-1.dll')
+ self.path('libaprutil-1.dll')
+ self.path('libapriconv-1.dll')
+ except RuntimeError, err:
+ pass
+ self.end_prefix()
+
+ # For google-perftools tcmalloc allocator.
+ self.path("../../libraries/i686-win32/lib/release/libtcmalloc_minimal.dll", dst="libtcmalloc_minimal.dll")
+
+ try:
+ if self.prefix("../../libraries/i686-win32/lib/release/msvcrt", dst=""):
+ self.path("*.dll")
+ self.path("*.manifest")
+ self.end_prefix()
+ except:
+ pass
+
+
+ # These need to be installed as a SxS assembly, currently a 'private' assembly.
+ # See http://msdn.microsoft.com/en-us/library/ms235291(VS.80).aspx
+ #~ if self.prefix(src=self.args['configuration'], dst=""):
+ #~ if self.args['configuration'] == 'Debug':
+ #~ self.path("msvcr80d.dll")
+ #~ self.path("msvcp80d.dll")
+ #~ self.path("Microsoft.VC80.DebugCRT.manifest")
+ #~ else:
+ #~ self.path("msvcr80.dll")
+ #~ self.path("msvcp80.dll")
+ #~ self.path("Microsoft.VC80.CRT.manifest")
+ #~ self.end_prefix()
+
+ # The config file name needs to match the exe's name.
+ #~ self.path(src="%s/secondlife-bin.exe.config" % self.args['configuration'], dst=self.final_exe() + ".config")
+
+ # Vivox runtimes
+ if self.prefix(src="vivox-runtime/i686-win32", dst=""):
+ self.path("SLVoice.exe")
+ self.path("alut.dll")
+ self.path("vivoxsdk.dll")
+ self.path("ortp.dll")
+ self.path("wrap_oal.dll")
+ self.end_prefix()
+
+ if self.args['extra_libraries'] != None:
+ print self.args['extra_libraries']
+ path_list = self.args['extra_libraries'].split('|')
+ for path in path_list:
+ path_pair = path.rsplit('/', 1)
+ if self.prefix(src=path_pair[0], dst=""):
+ self.path(path_pair[1])
+ self.end_prefix()
+
+ # pull in the crash logger and updater from other projects
+ self.path(src='../win_crash_logger/%s/windows-crash-logger.exe' % self.args['configuration'], dst="win_crash_logger.exe")
+ self.path(src='../win_updater/%s/windows-updater.exe' % self.args['configuration'], dst="updater.exe")
+
+
+ def nsi_file_commands(self, install=True):
+ def wpath(path):
+ if path.endswith('/') or path.endswith(os.path.sep):
+ path = path[:-1]
+ path = path.replace('/', '\\')
+ return path
+
+ result = ""
+ dest_files = [pair[1] for pair in self.file_list if pair[0] and os.path.isfile(pair[1])]
+ # sort deepest hierarchy first
+ dest_files.sort(lambda a,b: cmp(a.count(os.path.sep),b.count(os.path.sep)) or cmp(a,b))
+ dest_files.reverse()
+ out_path = None
+ for pkg_file in dest_files:
+ rel_file = os.path.normpath(pkg_file.replace(self.get_dst_prefix()+os.path.sep,''))
+ installed_dir = wpath(os.path.join('$INSTDIR', os.path.dirname(rel_file)))
+ pkg_file = wpath(os.path.normpath(pkg_file))
+ if installed_dir != out_path:
+ if install:
+ out_path = installed_dir
+ result += 'SetOutPath ' + out_path + '\n'
+ if install:
+ result += 'File ' + pkg_file + '\n'
+ else:
+ result += 'Delete ' + wpath(os.path.join('$INSTDIR', rel_file)) + '\n'
+ # at the end of a delete, just rmdir all the directories
+ if not install:
+ deleted_file_dirs = [os.path.dirname(pair[1].replace(self.get_dst_prefix()+os.path.sep,'')) for pair in self.file_list]
+ # find all ancestors so that we don't skip any dirs that happened to have no non-dir children
+ deleted_dirs = []
+ for d in deleted_file_dirs:
+ deleted_dirs.extend(path_ancestors(d))
+ # sort deepest hierarchy first
+ deleted_dirs.sort(lambda a,b: cmp(a.count(os.path.sep),b.count(os.path.sep)) or cmp(a,b))
+ deleted_dirs.reverse()
+ prev = None
+ for d in deleted_dirs:
+ if d != prev: # skip duplicates
+ result += 'RMDir ' + wpath(os.path.join('$INSTDIR', os.path.normpath(d))) + '\n'
+ prev = d
+
+ return result
+
+ def package_finish(self):
+ # a standard map of strings for replacing in the templates
+ substitution_strings = {
+ 'version' : '.'.join(self.args['version']),
+ 'version_short' : '.'.join(self.args['version'][:-1]),
+ 'version_dashes' : '-'.join(self.args['version']),
+ 'final_exe' : self.final_exe(),
+ 'grid':self.args['grid'],
+ 'grid_caps':self.args['grid'].upper(),
+ # escape quotes becase NSIS doesn't handle them well
+ 'flags':self.flags_list().replace('"', '$\\"'),
+ 'channel':self.channel(),
+ 'channel_oneword':self.channel_oneword(),
+ 'channel_unique':self.channel_unique(),
+ }
+
+ version_vars = """
+ !define INSTEXE "%(final_exe)s"
+ !define VERSION "%(version_short)s"
+ !define VERSION_LONG "%(version)s"
+ !define VERSION_DASHES "%(version_dashes)s"
+ """ % substitution_strings
+ installer_file = "%(channel_oneword)s_%(version_dashes)s_Setup.exe"
+ grid_vars_template = """
+ OutFile "%(installer_file)s"
+ !define VIEWERNAME "%(channel)s"
+ !define INSTFLAGS "%(flags)s"
+ !define INSTNAME "%(channel_oneword)s"
+ !define SHORTCUT "%(channel)s Viewer"
+ !define URLNAME "secondlife"
+ !define INSTALL_ICON "install_icon_singularity.ico"
+ !define UNINSTALL_ICON "install_icon_singularity.ico"
+ Caption "${VIEWERNAME} ${VERSION_LONG}"
+ """
+ if 'installer_name' in self.args:
+ installer_file = self.args['installer_name']
+ else:
+ installer_file = installer_file % substitution_strings
+ substitution_strings['installer_file'] = installer_file
+
+ tempfile = "secondlife_setup_tmp.nsi"
+ # the following replaces strings in the nsi template
+ # it also does python-style % substitution
+ self.replace_in("installers/windows/installer_template.nsi", tempfile, {
+ "%%VERSION%%":version_vars,
+ "%%SOURCE%%":self.get_src_prefix(),
+ "%%GRID_VARS%%":grid_vars_template % substitution_strings,
+ "%%INSTALL_FILES%%":self.nsi_file_commands(True),
+ "%%DELETE_FILES%%":self.nsi_file_commands(False)})
+
+ # We use the Unicode version of NSIS, available from
+ # http://www.scratchpaper.com/
+ try:
+ import _winreg as reg
+ NSIS_path = reg.QueryValue(reg.HKEY_LOCAL_MACHINE, r"SOFTWARE\NSIS\Unicode") + '\\makensis.exe'
+ self.run_command('"' + proper_windows_path(NSIS_path) + '" ' + self.dst_path_of(tempfile))
+ except:
+ try:
+ NSIS_path = os.environ['ProgramFiles'] + '\\NSIS\\Unicode\\makensis.exe'
+ self.run_command('"' + proper_windows_path(NSIS_path) + '" ' + self.dst_path_of(tempfile))
+ except:
+ NSIS_path = os.environ['ProgramFiles(X86)'] + '\\NSIS\\Unicode\\makensis.exe'
+ self.run_command('"' + proper_windows_path(NSIS_path) + '" ' + self.dst_path_of(tempfile))
+ # self.remove(self.dst_path_of(tempfile))
+ # If we're on a build machine, sign the code using our Authenticode certificate. JC
+ sign_py = os.path.expandvars("{SIGN_PY}")
+ if sign_py == "" or sign_py == "{SIGN_PY}":
+ sign_py = 'C:\\buildscripts\\code-signing\\sign.py'
+ if os.path.exists(sign_py):
+ self.run_command('python ' + sign_py + ' ' + self.dst_path_of(installer_file))
+ else:
+ print "Skipping code signing,", sign_py, "does not exist"
+ self.created_path(self.dst_path_of(installer_file))
+ self.package_file = installer_file
+
+
+class DarwinManifest(ViewerManifest):
+ def construct(self):
+ # copy over the build result (this is a no-op if run within the xcode script)
+ self.path(self.args['configuration'] + "/" + self.app_name() + ".app", dst="")
+
+ if self.prefix(src="", dst="Contents"): # everything goes in Contents
+ self.path(self.info_plist_name(), dst="Info.plist")
+
+ # copy additional libs in /Contents/MacOS/
+ self.path("../../libraries/universal-darwin/lib_release/libhunspell-1.2.dylib", dst="MacOS/libhunspell-1.2.dylib")
+ self.path("../../libraries/universal-darwin/lib_release/libndofdev.dylib", dst="MacOS/libndofdev.dylib")
+ #self.path("../../libraries/universal-darwin/lib_release/libvorbisenc.2.dylib", dst="MacOS/libvorbisenc.2.dylib")
+ #self.path("../../libraries/universal-darwin/lib_release/libvorbisfile.3.dylib", dst="MacOS/libvorbisfile.3.dylib")
+ #self.path("../../libraries/universal-darwin/lib_release/libvorbis.0.dylib", dst="MacOS/libvorbis.0.dylib")
+ #self.path("../../libraries/universal-darwin/lib_release/libogg.0.dylib", dst="MacOS/libogg.0.dylib")
+
+ # most everything goes in the Resources directory
+ if self.prefix(src="", dst="Resources"):
+ super(DarwinManifest, self).construct()
+
+ if self.prefix("cursors_mac"):
+ self.path("*.tif")
+ self.end_prefix("cursors_mac")
+
+ self.path("licenses-mac.txt", dst="licenses.txt")
+ self.path("featuretable_mac.txt")
+ self.path("SecondLife.nib")
+
+ # SG:TODO
+ self.path("../newview/res/singularity.icns", dst="singularity.icns")
+
+ # Translations
+ self.path("English.lproj")
+ self.path("German.lproj")
+ self.path("Japanese.lproj")
+ self.path("Korean.lproj")
+ self.path("da.lproj")
+ self.path("es.lproj")
+ self.path("fr.lproj")
+ self.path("hu.lproj")
+ self.path("it.lproj")
+ self.path("nl.lproj")
+ self.path("pl.lproj")
+ self.path("pt.lproj")
+ self.path("ru.lproj")
+ self.path("tr.lproj")
+ self.path("uk.lproj")
+ self.path("zh-Hans.lproj")
+
+ # SLVoice and vivox lols
+ self.path("vivox-runtime/universal-darwin/libalut.dylib", "libalut.dylib")
+ self.path("vivox-runtime/universal-darwin/libopenal.dylib", "libopenal.dylib")
+ self.path("vivox-runtime/universal-darwin/libortp.dylib", "libortp.dylib")
+ self.path("vivox-runtime/universal-darwin/libvivoxsdk.dylib", "libvivoxsdk.dylib")
+ self.path("vivox-runtime/universal-darwin/SLVoice", "SLVoice")
+
+ self.path("../llcommon/" + self.args['configuration'] + "/libllcommon.dylib", "libllcommon.dylib")
+
+ libfile = "lib%s.dylib"
+ libdir = "../../libraries/universal-darwin/lib_release"
+
+ for libfile in ("libapr-1.0.3.7.dylib",
+ "libaprutil-1.0.3.8.dylib",
+ "libexpat.0.5.0.dylib"):
+ self.path(os.path.join(libdir, libfile), libfile)
+
+ # For using FMOD for sound...but, fmod is proprietary so some might not use it...
+ try:
+ self.path(self.args['configuration'] + "/libfmodwrapper.dylib", "libfmodwrapper.dylib")
+ pass
+ except:
+ print "Skipping libfmodwrapper.dylib - not found"
+ pass
+
+ # our apps
+ try:
+ self.path("../mac_crash_logger/" + self.args['configuration'] + "/mac-crash-logger.app", "mac-crash-logger.app")
+ self.path("../mac_updater/" + self.args['configuration'] + "/mac-updater.app", "mac-updater.app")
+ except:
+ pass
+
+ # plugin launcher
+ self.path("../llplugin/slplugin/" + self.args['configuration'] + "/SLPlugin.app", "SLPlugin.app")
+
+ # dependencies on shared libs
+ mac_crash_logger_res_path = self.dst_path_of("mac-crash-logger.app/Contents/Resources")
+ slplugin_res_path = self.dst_path_of("SLPlugin.app/Contents/Resources")
+ for libfile in ("libllcommon.dylib",
+ "libapr-1.0.3.7.dylib",
+ "libaprutil-1.0.3.8.dylib",
+ "libexpat.0.5.0.dylib"):
+ target_lib = os.path.join('../../..', libfile)
+ self.run_command("ln -sf %(target)r %(link)r" %
+ {'target': target_lib,
+ 'link' : os.path.join(slplugin_res_path, libfile)}
+ )
+ #self.run_command("ln -sf %(target)r %(link)r" %
+ # {'target': target_lib,
+ # 'link' : os.path.join(mac_crash_logger_res_path, libfile)}
+ # )
+
+ # plugins
+ if self.prefix(src="", dst="llplugin"):
+ self.path("../plugins/filepicker/" + self.args['configuration'] + "/basic_plugin_filepicker.dylib", "basic_plugin_filepicker.dylib")
+ self.path("../plugins/quicktime/" + self.args['configuration'] + "/media_plugin_quicktime.dylib", "media_plugin_quicktime.dylib")
+ self.path("../plugins/webkit/" + self.args['configuration'] + "/media_plugin_webkit.dylib", "media_plugin_webkit.dylib")
+ self.path("../../libraries/universal-darwin/lib_release/libllqtwebkit.dylib", "libllqtwebkit.dylib")
+
+ self.end_prefix("llplugin")
+
+ # command line arguments for connecting to the proper grid
+ self.put_in_file(self.flags_list(), 'arguments.txt')
+
+ self.end_prefix("Resources")
+
+ self.end_prefix("Contents")
+
+ # NOTE: the -S argument to strip causes it to keep enough info for
+ # annotated backtraces (i.e. function names in the crash log). 'strip' with no
+ # arguments yields a slightly smaller binary but makes crash logs mostly useless.
+ # This may be desirable for the final release. Or not.
+ if self.buildtype().lower()=='release':
+ if ("package" in self.args['actions'] or
+ "unpacked" in self.args['actions']):
+ self.run_command('strip -S "%(viewer_binary)s"' %
+ { 'viewer_binary' : self.dst_path_of('Contents/MacOS/'+self.app_name())})
+
+ def app_name(self):
+ return "Singularity"
+
+ def info_plist_name(self):
+ return "Info-Singularity.plist"
+
+ def package_finish(self):
+ channel_standin = self.app_name()
+ if not self.default_channel_for_brand():
+ channel_standin = self.channel()
+
+ imagename=self.installer_prefix() + '_'.join(self.args['version'])
+
+ # See Ambroff's Hack comment further down if you want to create new bundles and dmg
+ volname=self.app_name() + " Installer" # DO NOT CHANGE without checking Ambroff's Hack comment further down
+
+ if self.default_channel_for_brand():
+ if not self.default_grid():
+ # beta case
+ imagename = imagename + '_' + self.args['grid'].upper()
+ else:
+ # first look, etc
+ imagename = imagename + '_' + self.channel_oneword().upper()
+
+ sparsename = imagename + ".sparseimage"
+ finalname = imagename + ".dmg"
+ # make sure we don't have stale files laying about
+ self.remove(sparsename, finalname)
+
+ self.run_command('hdiutil create "%(sparse)s" -volname "%(vol)s" -fs HFS+ -type SPARSE -megabytes 700 -layout SPUD' % {
+ 'sparse':sparsename,
+ 'vol':volname})
+
+ # mount the image and get the name of the mount point and device node
+ hdi_output = self.run_command('hdiutil attach -private "' + sparsename + '"')
+ devfile = re.search("/dev/disk([0-9]+)[^s]", hdi_output).group(0).strip()
+ volpath = re.search('HFS\s+(.+)', hdi_output).group(1).strip()
+
+ # Copy everything in to the mounted .dmg
+
+ if self.default_channel_for_brand() and not self.default_grid():
+ app_name = self.app_name() + " " + self.args['grid']
+ else:
+ app_name = channel_standin.strip()
+
+ # Hack:
+ # Because there is no easy way to coerce the Finder into positioning
+ # the app bundle in the same place with different app names, we are
+ # adding multiple .DS_Store files to svn. There is one for release,
+ # one for release candidate and one for first look. Any other channels
+ # will use the release .DS_Store, and will look broken.
+ # - Ambroff 2008-08-20
+ # Added a .DS_Store for snowglobe - Merov 2009-06-17
+
+ # We have a single branded installer for all snowglobe channels so snowglobe logic is a bit different
+ if (self.app_name()=="Snowglobe"):
+ dmg_template = os.path.join ('installers', 'darwin', 'snowglobe-dmg')
+ else:
+ dmg_template = os.path.join(
+ 'installers',
+ 'darwin',
+ '%s-dmg' % "".join(self.channel_unique().split()).lower())
+
+ if not os.path.exists (self.src_path_of(dmg_template)):
+ dmg_template = os.path.join ('installers', 'darwin', 'release-dmg')
+
+ for s,d in {self.get_dst_prefix():app_name + ".app",
+ os.path.join(dmg_template, "_VolumeIcon.icns"): ".VolumeIcon.icns",
+ os.path.join(dmg_template, "background.jpg"): "background.jpg",
+ os.path.join(dmg_template, "_DS_Store"): ".DS_Store"}.items():
+ print "Copying to dmg", s, d
+ self.copy_action(self.src_path_of(s), os.path.join(volpath, d))
+
+ # Hide the background image, DS_Store file, and volume icon file (set their "visible" bit)
+ self.run_command('SetFile -a V "' + os.path.join(volpath, ".VolumeIcon.icns") + '"')
+ self.run_command('SetFile -a V "' + os.path.join(volpath, "background.jpg") + '"')
+ self.run_command('SetFile -a V "' + os.path.join(volpath, ".DS_Store") + '"')
+
+ # Create the alias file (which is a resource file) from the .r
+ self.run_command('rez "' + self.src_path_of("installers/darwin/release-dmg/Applications-alias.r") + '" -o "' + os.path.join(volpath, "Applications") + '"')
+
+ # Set the alias file's alias and custom icon bits
+ self.run_command('SetFile -a AC "' + os.path.join(volpath, "Applications") + '"')
+
+ # Set the disk image root's custom icon bit
+ self.run_command('SetFile -a C "' + volpath + '"')
+
+ # Unmount the image
+ self.run_command('hdiutil detach -force "' + devfile + '"')
+
+ print "Converting temp disk image to final disk image"
+ self.run_command('hdiutil convert "%(sparse)s" -format UDZO -imagekey zlib-level=9 -o "%(final)s"' % {'sparse':sparsename, 'final':finalname})
+ # get rid of the temp file
+ self.package_file = finalname
+ self.remove(sparsename)
+
+class LinuxManifest(ViewerManifest):
+ def construct(self):
+ super(LinuxManifest, self).construct()
+ self.path("licenses-linux.txt","licenses.txt")
+
+ self.path("res/"+self.icon_name(),self.icon_name())
+ if self.prefix("linux_tools", dst=""):
+ self.path("client-readme.txt","README-linux.txt")
+ self.path("client-readme-voice.txt","README-linux-voice.txt")
+ self.path("client-readme-joystick.txt","README-linux-joystick.txt")
+ self.path("wrapper.sh",self.wrapper_name())
+ self.path("handle_secondlifeprotocol.sh")
+ self.path("register_secondlifeprotocol.sh")
+ self.end_prefix("linux_tools")
+
+ # Create an appropriate gridargs.dat for this package, denoting required grid.
+ self.put_in_file(self.flags_list(), 'gridargs.dat')
+
+ if self.buildtype().lower()=='release':
+ self.path("secondlife-stripped","bin/"+self.binary_name())
+ self.path("../linux_crash_logger/linux-crash-logger-stripped","linux-crash-logger.bin")
+ else:
+ self.path("secondlife-bin","bin/"+self.binary_name())
+ self.path("../linux_crash_logger/linux-crash-logger","linux-crash-logger.bin")
+
+ self.path("linux_tools/launch_url.sh","launch_url.sh")
+ self.path("../llplugin/slplugin/SLPlugin", "bin/SLPlugin")
+ if self.prefix("res-sdl"):
+ self.path("*")
+ # recurse
+ self.end_prefix("res-sdl")
+
+ # plugins
+ if self.prefix(src="", dst="bin/llplugin"):
+ self.path("../plugins/filepicker/libbasic_plugin_filepicker.so", "libbasic_plugin_filepicker.so")
+ self.path("../plugins/webkit/libmedia_plugin_webkit.so", "libmedia_plugin_webkit.so")
+ self.path("../plugins/gstreamer010/libmedia_plugin_gstreamer010.so", "libmedia_plugin_gstreamer.so")
+ self.end_prefix("bin/llplugin")
+
+ self.path("featuretable_linux.txt")
+
+ def wrapper_name(self):
+ return 'singularity'
+
+ def binary_name(self):
+ return 'singularity-do-not-run-directly'
+
+ def icon_name(self):
+ return "singularity_icon.png"
+
+ def package_finish(self):
+ if 'installer_name' in self.args:
+ installer_name = self.args['installer_name']
+ else:
+ installer_name_components = [self.installer_prefix(), self.args.get('arch')]
+ installer_name_components.extend(self.args['version'])
+ installer_name = "_".join(installer_name_components)
+ if self.default_channel():
+ if not self.default_grid():
+ installer_name += '_' + self.args['grid'].upper()
+ else:
+ installer_name += '_' + self.channel_oneword().upper()
+
+ if self.args['buildtype'].lower() in ['release', 'releasesse2']:
+ print "* Going strip-crazy on the packaged binaries, since this is a RELEASE build"
+ # makes some small assumptions about our packaged dir structure
+ self.run_command("find %(d)r/bin %(d)r/lib* -type f | xargs --no-run-if-empty strip --strip-unneeded" % {'d': self.get_dst_prefix()} )
+ self.run_command("find %(d)r/bin %(d)r/lib* -type f -not -name \\*.so | xargs --no-run-if-empty strip -s" % {'d': self.get_dst_prefix()} )
+
+ # Fix access permissions
+ self.run_command("""
+ find '%(dst)s' -type d -print0 | xargs -0 --no-run-if-empty chmod 755;
+ find '%(dst)s' -type f -perm 0700 -print0 | xargs -0 --no-run-if-empty chmod 0755;
+ find '%(dst)s' -type f -perm 0500 -print0 | xargs -0 --no-run-if-empty chmod 0555;
+ find '%(dst)s' -type f -perm 0600 -print0 | xargs -0 --no-run-if-empty chmod 0644;
+ find '%(dst)s' -type f -perm 0400 -print0 | xargs -0 --no-run-if-empty chmod 0444;
+ true""" % {'dst':self.get_dst_prefix() })
+ self.package_file = installer_name + '.tar.bz2'
+
+ # temporarily move directory tree so that it has the right
+ # name in the tarfile
+ self.run_command("mv '%(dst)s' '%(inst)s'" % {
+ 'dst': self.get_dst_prefix(),
+ 'inst': self.build_path_of(installer_name)})
+ try:
+ # --numeric-owner hides the username of the builder for
+ # security etc.
+ # I'm leaving this disabled for speed
+ #self.run_command("tar -C '%(dir)s' --numeric-owner -cjf "
+ # "'%(inst_path)s.tar.bz2' %(inst_name)s" % {
+ # 'dir': self.get_build_prefix(),
+ # 'inst_name': installer_name,
+ # 'inst_path':self.build_path_of(installer_name)})
+ print ''
+ finally:
+ self.run_command("mv '%(inst)s' '%(dst)s'" % {
+ 'dst': self.get_dst_prefix(),
+ 'inst': self.build_path_of(installer_name)})
+
+
+class Linux_i686Manifest(LinuxManifest):
+ def construct(self):
+ super(Linux_i686Manifest, self).construct()
+
+ self.path("../llcommon/libllcommon.so", "lib/libllcommon.so")
+
+ if (not self.standalone()) and self.prefix("../../libraries/i686-linux/lib_release_client", dst="lib"):
+
+ try:
+ self.path("libkdu_v42R.so", "libkdu.so")
+ pass
+ except:
+ print "Skipping libkdu_v42R.so - not found"
+ pass
+
+ try:
+ self.path("libfmod-3.75.so")
+ pass
+ except:
+ print "Skipping libfmod-3.75.so - not found"
+ pass
+
+ self.path("libapr-1.so.0")
+ self.path("libaprutil-1.so.0")
+ self.path("libdb-4.2.so")
+ self.path("libcrypto.so.0.9.7")
+ self.path("libexpat.so.1")
+ self.path("libhunspell-1.2.so.0.0.0", "libhunspell-1.2.so.0")
+ self.path("libssl.so.0.9.7")
+ #self.path("libuuid.so.1")
+ self.path("libSDL-1.2.so.0")
+ self.path("libELFIO.so")
+ #self.path("libopenjpeg.so.1.3.0", "libopenjpeg.so.1.3")
+ self.path("libalut.so")
+ self.path("libopenal.so.1")
+ self.path("libtcmalloc_minimal.so.0")
+ self.path("libtcmalloc_minimal.so.0.2.2")
+ self.end_prefix("lib")
+
+
+ # Vivox runtimes
+ if self.prefix(src="vivox-runtime/i686-linux", dst="bin"):
+ self.path("SLVoice")
+ self.end_prefix()
+ if self.prefix(src="vivox-runtime/i686-linux", dst="lib"):
+ self.path("libortp.so")
+ self.path("libvivoxsdk.so")
+ self.end_prefix("lib")
+
+
+class Linux_x86_64Manifest(LinuxManifest):
+ def construct(self):
+ super(Linux_x86_64Manifest, self).construct()
+
+ self.path("../llcommon/libllcommon.so", "lib64/libllcommon.so")
+
+ if (not self.standalone()) and self.prefix("../../libraries/x86_64-linux/lib_release_client", dst="lib64"):
+ self.path("libapr-1.so.0")
+ self.path("libaprutil-1.so.0")
+ self.path("libdb-4.2.so")
+ self.path("libcrypto.so.0.9.8")
+ self.path("libexpat.so.1")
+ self.path("libhunspell-1.2.so.0.0.0", "libhunspell-1.2.so.0")
+ self.path("libssl.so.0.9.8")
+ self.path("libuuid.so", "libuuid.so.1")
+ self.path("libSDL-1.2.so.0")
+ self.path("libELFIO.so")
+ self.path("libjpeg.so.7")
+ self.path("libpng12.so.0")
+ self.path("libopenjpeg.so.2")
+ self.path("libxml2.so.2")
+ #self.path("libz.so.1") #not needed
+
+ # OpenAL
+ self.path("libopenal.so.1")
+ self.path("libalut.so.0")
+
+ self.end_prefix("lib64")
+
+ # Vivox runtimes and libs
+ if self.prefix(src="vivox-runtime/i686-linux", dst="bin"):
+ self.path("SLVoice")
+ self.end_prefix("bin")
+
+ if self.prefix(src="vivox-runtime/i686-linux", dst="lib32"):
+ #self.path("libalut.so")
+ self.path("libortp.so")
+ self.path("libvivoxsdk.so")
+ self.end_prefix("lib32")
+
+ # 32bit libs needed for voice
+ if self.prefix("../../libraries/x86_64-linux/lib_release_client/32bit-compat", dst="lib32"):
+ self.path("libalut.so")
+ self.path("libidn.so.11")
+ self.path("libopenal.so.1")
+ # self.path("libortp.so")
+ self.path("libuuid.so.1")
+ self.end_prefix("lib32")
+
+if __name__ == "__main__":
+ main()
From a4363de59e2130aafe161552ffa2fcf77a9a6390 Mon Sep 17 00:00:00 2001
From: Drake Arconis
Date: Sun, 19 Feb 2012 15:59:47 -0500
Subject: [PATCH 3/9] Updated APR and Zlib prebuilts.
---
indra/cmake/APR.cmake | 8 +--
indra/newview/viewer_manifest.py | 8 +--
install.xml | 114 +++++++++++++++----------------
3 files changed, 65 insertions(+), 65 deletions(-)
diff --git a/indra/cmake/APR.cmake b/indra/cmake/APR.cmake
index d1f089891..5c434f4bf 100644
--- a/indra/cmake/APR.cmake
+++ b/indra/cmake/APR.cmake
@@ -29,12 +29,12 @@ else (STANDALONE)
)
elseif (DARWIN)
set(APR_LIBRARIES
- debug ${ARCH_PREBUILT_DIRS_DEBUG}/libapr-1.0.3.7.dylib
- optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libapr-1.0.3.7.dylib
+ debug ${ARCH_PREBUILT_DIRS_DEBUG}/libapr-1.0.dylib
+ optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libapr-1.0.dylib
)
set(APRUTIL_LIBRARIES
- debug ${ARCH_PREBUILT_DIRS_DEBUG}/libaprutil-1.0.3.8.dylib
- optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libaprutil-1.0.3.8.dylib
+ debug ${ARCH_PREBUILT_DIRS_DEBUG}/libaprutil-1.0.dylib
+ optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libaprutil-1.0.dylib
)
set(APRICONV_LIBRARIES iconv)
else (WINDOWS)
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index b492ddaef..8f49f94a9 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -514,8 +514,8 @@ class DarwinManifest(ViewerManifest):
libfile = "lib%s.dylib"
libdir = "../../libraries/universal-darwin/lib_release"
- for libfile in ("libapr-1.0.3.7.dylib",
- "libaprutil-1.0.3.8.dylib",
+ for libfile in ("libapr-1.0.dylib",
+ "libaprutil-1.0.dylib",
"libexpat.0.5.0.dylib"):
self.path(os.path.join(libdir, libfile), libfile)
@@ -541,8 +541,8 @@ class DarwinManifest(ViewerManifest):
mac_crash_logger_res_path = self.dst_path_of("mac-crash-logger.app/Contents/Resources")
slplugin_res_path = self.dst_path_of("SLPlugin.app/Contents/Resources")
for libfile in ("libllcommon.dylib",
- "libapr-1.0.3.7.dylib",
- "libaprutil-1.0.3.8.dylib",
+ "libapr-1.0.dylib",
+ "libaprutil-1.0.dylib",
"libexpat.0.5.0.dylib"):
target_lib = os.path.join('../../..', libfile)
self.run_command("ln -sf %(target)r %(link)r" %
diff --git a/install.xml b/install.xml
index d7ce8c54d..23be3cc8d 100644
--- a/install.xml
+++ b/install.xml
@@ -29,7 +29,7 @@
- freeglut
+ freeglut
@@ -200,14 +200,14 @@
md5sum
2cad51575b429be4fdadb5d63da1c739
url
- https://github.com/downloads/siana/SingularityViewer/boost-1.45.0-darwin-20110604.tar.bz2
+ https://github.com/downloads/siana/SingularityViewer/boost-1.45.0-darwin-20110604.tar.bz2
linux
md5sum
a2d2fff5cc5555ffd9865daedfcd0dd5
url
- https://github.com/downloads/siana/SingularityViewer/boost-1.45.0-linux-20110604.tar.bz2
+ https://github.com/downloads/siana/SingularityViewer/boost-1.45.0-linux-20110604.tar.bz2
windows
@@ -218,46 +218,46 @@
- curl
-
- copyright
- Copyright (c) 1996 - 2008, Daniel Stenberg, <daniel@haxx.se>.
- description
- Client-side URL transfer library. Handles moving data across the net in many different protocols. Used to GET/POST/PUT/DELETE web resources.
- license
- curl
- packages
-
- darwin
-
- md5sum
- 525f6b18ea5af8fbd691c2ac1769056c
- url
- https://github.com/downloads/Shyotl/SingularityViewer/curl-7.20.1-darwin-20100606.tar.bz2
-
- linux
-
- md5sum
- 6244eec15fb26f9577785625fdb38f78
- url
- https://github.com/downloads/Shyotl/SingularityViewer/curl-7.20.1-linux-20100527.tar.bz2
-
- linux64
-
- md5sum
- 8a28849f4b9d99601dbc8db9d6a2f9ba
- url
- https://github.com/downloads/Shyotl/SingularityViewer/curl-7.16.4a-linux64-20090303.tar.bz2
-
- windows
-
- md5sum
- 60ed73408c4050ff9c96f26771fd6b46
- url
- https://github.com/downloads/siana/SingularityViewer/curl-7.21.1-windows-20110504.tar.bz2
-
-
-
+ curl
+
+ copyright
+ Copyright (c) 1996 - 2008, Daniel Stenberg, <daniel@haxx.se>.
+ description
+ Client-side URL transfer library. Handles moving data across the net in many different protocols. Used to GET/POST/PUT/DELETE web resources.
+ license
+ curl
+ packages
+
+ darwin
+
+ md5sum
+ 525f6b18ea5af8fbd691c2ac1769056c
+ url
+ https://github.com/downloads/Shyotl/SingularityViewer/curl-7.20.1-darwin-20100606.tar.bz2
+
+ linux
+
+ md5sum
+ 6244eec15fb26f9577785625fdb38f78
+ url
+ https://github.com/downloads/Shyotl/SingularityViewer/curl-7.20.1-linux-20100527.tar.bz2
+
+ linux64
+
+ md5sum
+ 8a28849f4b9d99601dbc8db9d6a2f9ba
+ url
+ https://github.com/downloads/Shyotl/SingularityViewer/curl-7.16.4a-linux64-20090303.tar.bz2
+
+ windows
+
+ md5sum
+ 60ed73408c4050ff9c96f26771fd6b46
+ url
+ https://github.com/downloads/siana/SingularityViewer/curl-7.21.1-windows-20110504.tar.bz2
+
+
+
dbghelp
copyright
@@ -546,14 +546,14 @@
md5sum
b190d8a0dce8dd8b514d2adb2c74b8d8
url
- http://sldev.free.fr/libraries/google-perftools-1.8.3-linux-20110924.tar.bz2
+ http://sldev.free.fr/libraries/google-perftools-1.8.3-linux-20110924.tar.bz2
windows
md5sum
4f787437a5e063ccde6637dfb1ebc01d
url
- https://bitbucket.org/Ansariel/phoenix-prebuilts/downloads/google_perftools-1.8-windows-20111005.tar.bz2
+ https://bitbucket.org/Ansariel/phoenix-prebuilts/downloads/google_perftools-1.8-windows-20111005.tar.bz2
@@ -995,7 +995,7 @@ anguage Infrstructure (CLI) international standard
md5sum
38abfe002ba073b6824016db98269972
url
- http://imprudenceviewer.org/download/libs/ndofdev-linux32-0.3.1-20100817.tar.bz2
+ http://imprudenceviewer.org/download/libs/ndofdev-linux32-0.3.1-20100817.tar.bz2
linux64
@@ -1028,14 +1028,14 @@ anguage Infrstructure (CLI) international standard
md5sum
5a154313bc30eacd8cfa1acd852ecd3e
url
- https://github.com/downloads/siana/SingularityViewer/ogg_vorbis-1.2.2-1.3.2-darwin-20110616.tar.bz2
+ https://github.com/downloads/siana/SingularityViewer/ogg_vorbis-1.2.2-1.3.2-darwin-20110616.tar.bz2
linux
md5sum
712b1d30790e9de83fea84ec3bc8fab0
url
- https://github.com/downloads/siana/SingularityViewer/ogg_vorbis-1.2.2-1.3.2-linux-20110616.tar.bz2
+ https://github.com/downloads/siana/SingularityViewer/ogg_vorbis-1.2.2-1.3.2-linux-20110616.tar.bz2
linux64
@@ -1227,10 +1227,10 @@ anguage Infrstructure (CLI) international standard
32bitcompatibilitylibs
copyright
- Copyrights: Libidn: Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
- Simon Josefsson. License GPL v3.0.
- Freealut, libuuid, openal-soft: see copyright and license of the
- according main packages.
+ Copyrights: Libidn: Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+ Simon Josefsson. License GPL v3.0.
+ Freealut, libuuid, openal-soft: see copyright and license of the
+ according main packages.
description
32bit libraries needed for using voice
@@ -1300,9 +1300,9 @@ anguage Infrstructure (CLI) international standard
darwin
md5sum
- c844e1b05723ce078dbbd5aea9cdd3ad
+ 58ef62004b508b234039f6a313d852eb
url
- http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/zlib-1.1.4-darwin-20080818.tar.bz2
+ https://github.com/downloads/LightDrake/SingularityViewer/zlib-1.2.5-darwin-20110211.tar.bz2
linux
From 665569dfc7ae6e01ce7d5788b32414804d5ae989 Mon Sep 17 00:00:00 2001
From: Drake Arconis
Date: Sun, 19 Feb 2012 17:07:42 -0500
Subject: [PATCH 4/9] I forgot why I made these.
---
indra/cmake/00-Common.cmake | 6 +++---
indra/cmake/Boost.cmake | 2 +-
indra/cmake/DirectX.cmake | 4 ++--
indra/cmake/LLCommon.cmake | 1 +
indra/cmake/LLPlugin.cmake | 4 ++--
indra/cmake/Python.cmake | 1 -
6 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake
index 1f9854be8..18cc4c695 100644
--- a/indra/cmake/00-Common.cmake
+++ b/indra/cmake/00-Common.cmake
@@ -158,10 +158,10 @@ if (LINUX)
add_definitions(-D_FORTIFY_SOURCE=2)
endif (NOT ${GXX_VERSION} MATCHES " 4.1.*Red Hat")
endif (${GXX_VERSION} STREQUAL ${CXX_VERSION})
-
- #Lets actualy get a numerical version of gxx's version
+
+ #Lets actually get a numerical version of gxx's version
STRING(REGEX REPLACE ".* ([0-9])\\.([0-9])\\.([0-9]).*" "\\1\\2\\3" CXX_VERSION ${CXX_VERSION})
-
+
#gcc 4.3 and above don't like the LL boost
if(${CXX_VERSION} GREATER 429)
add_definitions(-Wno-parentheses)
diff --git a/indra/cmake/Boost.cmake b/indra/cmake/Boost.cmake
index 0cd10bd6c..1275d0547 100644
--- a/indra/cmake/Boost.cmake
+++ b/indra/cmake/Boost.cmake
@@ -10,7 +10,7 @@ if (STANDALONE)
set(BOOST_FILESYSTEM_LIBRARY boost_filesystem-mt)
set(BOOST_PROGRAM_OPTIONS_LIBRARY boost_program_options-mt)
set(BOOST_REGEX_LIBRARY boost_regex-mt)
- set(BOOST_SYSTEM_LIBRARY boost_system-mt)
+ set(BOOST_SYSTEM_LIBRARY boost_system-mt)
else (STANDALONE)
use_prebuilt_binary(boost)
set(Boost_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include)
diff --git a/indra/cmake/DirectX.cmake b/indra/cmake/DirectX.cmake
index 5f538c80a..e45575595 100644
--- a/indra/cmake/DirectX.cmake
+++ b/indra/cmake/DirectX.cmake
@@ -3,7 +3,7 @@
if (VIEWER AND WINDOWS)
find_path(DIRECTX_INCLUDE_DIR dxdiag.h
"$ENV{DXSDK_DIR}/Include"
- "$ENV{PROGRAMFILES}/Microsoft DirectX SDK (June 2010)/Include"
+ "$ENV{PROGRAMFILES}/Microsoft DirectX SDK (June 2010)/Include"
"$ENV{PROGRAMFILES}/Microsoft DirectX SDK (March 2009)/Include"
"$ENV{PROGRAMFILES}/Microsoft DirectX SDK (August 2008)/Include"
"$ENV{PROGRAMFILES}/Microsoft DirectX SDK (June 2008)/Include"
@@ -25,7 +25,7 @@ if (VIEWER AND WINDOWS)
find_path(DIRECTX_LIBRARY_DIR dxguid.lib
"$ENV{DXSDK_DIR}/Lib/x86"
- "$ENV{PROGRAMFILES}/Microsoft DirectX SDK (June 2010)/Lib/x86"
+ "$ENV{PROGRAMFILES}/Microsoft DirectX SDK (June 2010)/Lib/x86"
"$ENV{PROGRAMFILES}/Microsoft DirectX SDK (March 2009)/Lib/x86"
"$ENV{PROGRAMFILES}/Microsoft DirectX SDK (August 2008)/Lib/x86"
"$ENV{PROGRAMFILES}/Microsoft DirectX SDK (June 2008)/Lib/x86"
diff --git a/indra/cmake/LLCommon.cmake b/indra/cmake/LLCommon.cmake
index 58316a489..b1bb1b6a9 100644
--- a/indra/cmake/LLCommon.cmake
+++ b/indra/cmake/LLCommon.cmake
@@ -14,6 +14,7 @@ endif (DARWIN)
set(LLCOMMON_INCLUDE_DIRS
${LIBS_OPEN_DIR}/cwdebug
${LIBS_OPEN_DIR}/llcommon
+ ${APRUTIL_INCLUDE_DIR}
${APR_INCLUDE_DIR}
${Boost_INCLUDE_DIRS}
)
diff --git a/indra/cmake/LLPlugin.cmake b/indra/cmake/LLPlugin.cmake
index 7ee404b9b..399cb332d 100644
--- a/indra/cmake/LLPlugin.cmake
+++ b/indra/cmake/LLPlugin.cmake
@@ -8,7 +8,7 @@ set(LLPLUGIN_INCLUDE_DIRS
if (LINUX)
# In order to support using ld.gold on linux, we need to explicitely
# specify all libraries that llplugin uses.
- set(LLPLUGIN_LIBRARIES llplugin pthread)
+ set(LLPLUGIN_LIBRARIES llplugin pthread)
else (LINUX)
- set(LLPLUGIN_LIBRARIES llplugin)
+ set(LLPLUGIN_LIBRARIES llplugin)
endif (LINUX)
diff --git a/indra/cmake/Python.cmake b/indra/cmake/Python.cmake
index a84ab64aa..748c8c2be 100644
--- a/indra/cmake/Python.cmake
+++ b/indra/cmake/Python.cmake
@@ -19,7 +19,6 @@ if (WINDOWS)
[HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.5\\InstallPath]
[HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.4\\InstallPath]
[HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.3\\InstallPath]
-
)
elseif (EXISTS /etc/debian_version)
# On Debian and Ubuntu, avoid Python 2.4 if possible.
From c6d6eed7d33121ac2bbd466ac2e49cccd6f6d921 Mon Sep 17 00:00:00 2001
From: Drake Arconis
Date: Sun, 19 Feb 2012 19:43:53 -0500
Subject: [PATCH 5/9] This works for now. Need to do more testing.
---
indra/newview/app_settings/settings.xml | 54 ++-
indra/newview/lltranslate.cpp | 469 ++++++++++++++++++------
indra/newview/lltranslate.h | 372 ++++++++++++++-----
indra/newview/llviewermessage.cpp | 26 +-
4 files changed, 696 insertions(+), 225 deletions(-)
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 2b521fed4..7553e8816 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -1,16 +1,15 @@
- Include
-
- settings_ascent.xml
- settings_ascent_coa.xml
- settings_sh.xml
- settings_rlv.xml
-
-
- SianaRenderDeferredInvisiprim
-
+ Include
+
+ settings_ascent.xml
+ settings_ascent_coa.xml
+ settings_sh.xml
+ settings_rlv.xml
+
+ SianaRenderDeferredInvisiprim
+
Comment
Support invisiprims in deferred mode
Persist
@@ -7525,12 +7524,45 @@
Comment
Translate incoming chat messages
Persist
- 0
+ 1
Type
Boolean
Value
0
+ TranslationService
+
+ Comment
+ Translation API to use. (google|bing)
+ Persist
+ 1
+ Type
+ String
+ Value
+ bing
+
+ GoogleTranslateAPIKey
+
+ Comment
+ Google Translate API key
+ Persist
+ 1
+ Type
+ String
+ Value
+
+
+ BingTranslateAPIKey
+
+ Comment
+ Bing AppID to use with the Microsoft Translator API
+ Persist
+ 1
+ Type
+ String
+ Value
+
+
LastFeatureVersion
Comment
diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp
index 5a537ae95..fcff3a0c7 100644
--- a/indra/newview/lltranslate.cpp
+++ b/indra/newview/lltranslate.cpp
@@ -2,136 +2,401 @@
* @file lltranslate.cpp
* @brief Functions for translating text via Google Translate.
*
-* $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$
-*/
+ * $LicenseInfo:firstyear=2009&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, 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$
+ */
#include "llviewerprecompiledheaders.h"
-#include "llbufferstream.h"
#include "lltranslate.h"
+
+#include
+
+#include "llbufferstream.h"
+#include "lltrans.h"
#include "llui.h"
-#include "sgversion.h"
+#include "llviewercontrol.h"
#include "llweb.h"
-//
-#include "llviewercontrol.h"
-//
+#include "sgversion.h"
-// These two are concatenated with the language specifiers to form a complete Google Translate URL
-const char* LLTranslate::m_GoogleURL = "http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q=";
-const char* LLTranslate::m_GoogleLangSpec = "&langpair=";
-float LLTranslate::m_GoogleTimeout = 10;
+#include "jsoncpp/reader.h"
-LLSD LLTranslate::m_Header;
-// These constants are for the GET header.
-const char* LLTranslate::m_AcceptHeader = "Accept";
-const char* LLTranslate::m_AcceptType = "text/plain";
-const char* LLTranslate::m_AgentHeader = "User-Agent";
-
-// These constants are in the JSON returned from Google
-const char* LLTranslate::m_GoogleData = "responseData";
-const char* LLTranslate::m_GoogleTranslation = "translatedText";
-const char* LLTranslate::m_GoogleLanguage = "detectedSourceLanguage";
-
-//static
-void LLTranslate::translateMessage(LLHTTPClient::ResponderPtr &result, const std::string &fromLang, const std::string &toLang, const std::string &mesg)
+// virtual
+void LLGoogleTranslationHandler::getTranslateURL(
+ std::string &url,
+ const std::string &from_lang,
+ const std::string &to_lang,
+ const std::string &text) const
{
- std::string url;
- getTranslateUrl(url, fromLang, toLang, mesg);
-
-//
- std::string user_agent = gCurrentVersion;
-//
-
- if (!m_Header.size())
+ url = std::string("https://www.googleapis.com/language/translate/v2?key=")
+ + getAPIKey() + "&q=" + LLURI::escape(text) + "&target=" + to_lang;
+ if (!from_lang.empty())
{
- m_Header.insert(m_AcceptHeader, LLSD(m_AcceptType));
- m_Header.insert(m_AgentHeader, LLSD(user_agent));
- }
-
- LLHTTPClient::get(url, result, m_Header, m_GoogleTimeout);
-}
-
-//static
-void LLTranslate::getTranslateUrl(std::string &translateUrl, const std::string &fromLang, const std::string &toLang, const std::string &mesg)
-{
- std::string escaped_mesg = LLWeb::curlEscape(mesg);
-
- translateUrl = m_GoogleURL
- + escaped_mesg + m_GoogleLangSpec
- + fromLang // 'from' language; empty string for auto
- + "%7C" // |
- + toLang; // 'to' language
-}
-
-//static
-void LLTranslate::stringReplaceAll(std::string& context, const std::string& from, const std::string& to)
-{
- size_t lookHere = 0;
- size_t foundHere;
-
- while((foundHere = context.find(from, lookHere))
- != std::string::npos) {
- context.replace(foundHere, from.size(), to);
- lookHere = foundHere + to.size();
+ url += "&source=" + from_lang;
}
}
-//static
-BOOL LLTranslate::parseGoogleTranslate(const std::string result, std::string &translation, std::string &detectedLanguage)
+// virtual
+void LLGoogleTranslationHandler::getKeyVerificationURL(
+ std::string& url,
+ const std::string& key) const
+{
+ url = std::string("https://www.googleapis.com/language/translate/v2/languages?key=")
+ + key + "&target=en";
+}
+
+// virtual
+bool LLGoogleTranslationHandler::parseResponse(
+ int& status,
+ const std::string& body,
+ std::string& translation,
+ std::string& detected_lang,
+ std::string& err_msg) const
{
Json::Value root;
Json::Reader reader;
- BOOL parsingSuccessful = reader.parse(result, root );
- if ( !parsingSuccessful )
+
+ if (!reader.parse(body, root))
{
- LL_WARNS("JSON") << reader.getFormatedErrorMessages() << LL_ENDL;
- return FALSE;
+ err_msg = reader.getFormatedErrorMessages();
+ return false;
}
- translation = root[m_GoogleData].get(m_GoogleTranslation, "").asString();
- detectedLanguage = root[m_GoogleData].get(m_GoogleLanguage, "").asString();
- return TRUE;
+ if (!root.isObject()) // empty response? should not happen
+ {
+ return false;
+ }
+
+ if (status != STATUS_OK)
+ {
+ // Request failed. Extract error message from the response.
+ parseErrorResponse(root, status, err_msg);
+ return false;
+ }
+
+ // Request succeeded, extract translation from the response.
+ return parseTranslation(root, translation, detected_lang);
+}
+
+// virtual
+bool LLGoogleTranslationHandler::isConfigured() const
+{
+ return !getAPIKey().empty();
+}
+
+// static
+void LLGoogleTranslationHandler::parseErrorResponse(
+ const Json::Value& root,
+ int& status,
+ std::string& err_msg)
+{
+ const Json::Value& error = root.get("error", 0);
+ if (!error.isObject() || !error.isMember("message") || !error.isMember("code"))
+ {
+ return;
+ }
+
+ err_msg = error["message"].asString();
+ status = error["code"].asInt();
+}
+
+// static
+bool LLGoogleTranslationHandler::parseTranslation(
+ const Json::Value& root,
+ std::string& translation,
+ std::string& detected_lang)
+{
+ // JsonCpp is prone to aborting the program on failed assertions,
+ // so be super-careful and verify the response format.
+ const Json::Value& data = root.get("data", 0);
+ if (!data.isObject() || !data.isMember("translations"))
+ {
+ return false;
+ }
+
+ const Json::Value& translations = data["translations"];
+ if (!translations.isArray() || translations.size() == 0)
+ {
+ return false;
+ }
+
+ const Json::Value& first = translations[0U];
+ if (!first.isObject() || !first.isMember("translatedText"))
+ {
+ return false;
+ }
+
+ translation = first["translatedText"].asString();
+ detected_lang = first.get("detectedSourceLanguage", "").asString();
+ return true;
+}
+
+// static
+std::string LLGoogleTranslationHandler::getAPIKey()
+{
+ return gSavedSettings.getString("GoogleTranslateAPIKey");
+}
+
+// virtual
+void LLBingTranslationHandler::getTranslateURL(
+ std::string &url,
+ const std::string &from_lang,
+ const std::string &to_lang,
+ const std::string &text) const
+{
+ url = std::string("http://api.microsofttranslator.com/v2/Http.svc/Translate?appId=")
+ + getAPIKey() + "&text=" + LLURI::escape(text) + "&to=" + to_lang;
+ if (!from_lang.empty())
+ {
+ url += "&from=" + from_lang;
+ }
+}
+
+// virtual
+void LLBingTranslationHandler::getKeyVerificationURL(
+ std::string& url,
+ const std::string& key) const
+{
+ url = std::string("http://api.microsofttranslator.com/v2/Http.svc/GetLanguagesForTranslate?appId=")
+ + key;
+}
+
+// virtual
+bool LLBingTranslationHandler::parseResponse(
+ int& status,
+ const std::string& body,
+ std::string& translation,
+ std::string& detected_lang,
+ std::string& err_msg) const
+{
+ if (status != STATUS_OK)
+ {
+ static const std::string MSG_BEGIN_MARKER = "Message: ";
+ size_t begin = body.find(MSG_BEGIN_MARKER);
+ if (begin != std::string::npos)
+ {
+ begin += MSG_BEGIN_MARKER.size();
+ }
+ else
+ {
+ begin = 0;
+ err_msg.clear();
+ }
+ size_t end = body.find("
", begin);
+ err_msg = body.substr(begin, end-begin);
+ LLStringUtil::replaceString(err_msg, "
", ""); // strip CR
+ return false;
+ }
+
+ // Sample response: Hola
+ size_t begin = body.find(">");
+ if (begin == std::string::npos || begin >= (body.size() - 1))
+ {
+ begin = 0;
+ }
+ else
+ {
+ ++begin;
+ }
+
+ size_t end = body.find("", begin);
+
+ detected_lang = ""; // unsupported by this API
+ translation = body.substr(begin, end-begin);
+ LLStringUtil::replaceString(translation, "
", ""); // strip CR
+ return true;
+}
+
+// virtual
+bool LLBingTranslationHandler::isConfigured() const
+{
+ return !getAPIKey().empty();
+}
+
+// static
+std::string LLBingTranslationHandler::getAPIKey()
+{
+ return gSavedSettings.getString("BingTranslateAPIKey");
+}
+
+LLTranslate::TranslationReceiver::TranslationReceiver(const std::string& from_lang, const std::string& to_lang)
+: mFromLang(from_lang)
+, mToLang(to_lang)
+, mHandler(LLTranslate::getPreferredHandler())
+{
+}
+
+// virtual
+void LLTranslate::TranslationReceiver::completedRaw(
+ U32 http_status,
+ const std::string& reason,
+ const LLChannelDescriptors& channels,
+ const LLIOPipe::buffer_ptr_t& buffer)
+{
+ LLBufferStream istr(channels, buffer.get());
+ std::stringstream strstrm;
+ strstrm << istr.rdbuf();
+
+ const std::string body = strstrm.str();
+ std::string translation, detected_lang, err_msg;
+ int status = http_status;
+ LL_DEBUGS("Translate") << "HTTP status: " << status << " " << reason << LL_ENDL;
+ LL_DEBUGS("Translate") << "Response body: " << body << LL_ENDL;
+ if (mHandler.parseResponse(status, body, translation, detected_lang, err_msg))
+ {
+ // Fix up the response
+ LLStringUtil::replaceString(translation, "<", "<");
+ LLStringUtil::replaceString(translation, ">",">");
+ LLStringUtil::replaceString(translation, ""","\"");
+ LLStringUtil::replaceString(translation, "'","'");
+ LLStringUtil::replaceString(translation, "&","&");
+ LLStringUtil::replaceString(translation, "'","'");
+
+ handleResponse(translation, detected_lang);
+ }
+ else
+ {
+ if (err_msg.empty())
+ {
+ err_msg = LLTrans::getString("TranslationResponseParseError");
+ }
+
+ llwarns << "Translation request failed: " << err_msg << llendl;
+ handleFailure(status, err_msg);
+ }
+}
+
+LLTranslate::KeyVerificationReceiver::KeyVerificationReceiver(EService service)
+: mService(service)
+{
+}
+
+LLTranslate::EService LLTranslate::KeyVerificationReceiver::getService() const
+{
+ return mService;
+}
+
+// virtual
+void LLTranslate::KeyVerificationReceiver::completedRaw(
+ U32 http_status,
+ const std::string& reason,
+ const LLChannelDescriptors& channels,
+ const LLIOPipe::buffer_ptr_t& buffer)
+{
+ bool ok = (http_status == 200);
+ setVerificationStatus(ok);
+}
+
+//static
+void LLTranslate::translateMessage(
+ TranslationReceiverPtr &receiver,
+ const std::string &from_lang,
+ const std::string &to_lang,
+ const std::string &mesg)
+{
+ std::string url;
+ receiver->mHandler.getTranslateURL(url, from_lang, to_lang, mesg);
+
+ LL_DEBUGS("Translate") << "Sending translation request: " << url << LL_ENDL;
+ sendRequest(url, receiver);
+}
+
+// static
+void LLTranslate::verifyKey(
+ KeyVerificationReceiverPtr& receiver,
+ const std::string& key)
+{
+ std::string url;
+ const LLTranslationAPIHandler& handler = getHandler(receiver->getService());
+ handler.getKeyVerificationURL(url, key);
+
+ LL_DEBUGS("Translate") << "Sending key verification request: " << url << LL_ENDL;
+ sendRequest(url, receiver);
}
//static
std::string LLTranslate::getTranslateLanguage()
{
- std::string language = "en";
- if (LLUI::sConfigGroup)
+ std::string language = gSavedSettings.getString("TranslateLanguage");
+ if (language.empty() || language == "default")
{
- language = LLUI::sConfigGroup->getString("TranslateLanguage");
- if (language.empty() || language == "default")
- {
- language = LLUI::getLanguage();
- }
+ language = LLUI::getLanguage();
}
language = language.substr(0,2);
return language;
}
+// static
+bool LLTranslate::isTranslationConfigured()
+{
+ return getPreferredHandler().isConfigured();
+}
+
+// static
+const LLTranslationAPIHandler& LLTranslate::getPreferredHandler()
+{
+ EService service = SERVICE_BING;
+
+ std::string service_str = gSavedSettings.getString("TranslationService");
+ if (service_str == "google")
+ {
+ service = SERVICE_GOOGLE;
+ }
+
+ return getHandler(service);
+}
+
+// static
+const LLTranslationAPIHandler& LLTranslate::getHandler(EService service)
+{
+ static LLGoogleTranslationHandler google;
+ static LLBingTranslationHandler bing;
+
+ if (service == SERVICE_GOOGLE)
+ {
+ return google;
+ }
+
+ return bing;
+}
+
+// static
+void LLTranslate::sendRequest(const std::string& url, LLHTTPClient::ResponderPtr responder)
+{
+ static const float REQUEST_TIMEOUT = 5;
+ static LLSD sHeader;
+
+ if (!sHeader.size())
+ {
+ std::string user_agent = llformat("%s %d.%d.%d (%d)",
+ gVersionChannel,
+ gVersionMajor,
+ gVersionMinor,
+ gVersionPatch,
+ gVersionBuild);
+
+ sHeader.insert("Accept", "text/plain");
+ sHeader.insert("User-Agent", user_agent);
+ }
+
+ LLHTTPClient::get(url, responder, sHeader, REQUEST_TIMEOUT);
+}
diff --git a/indra/newview/lltranslate.h b/indra/newview/lltranslate.h
index 2723c43ff..870cc1fae 100644
--- a/indra/newview/lltranslate.h
+++ b/indra/newview/lltranslate.h
@@ -2,33 +2,27 @@
* @file lltranslate.h
* @brief Human language translation class and JSON response receiver.
*
-* $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$
-*/
+ * $LicenseInfo:firstyear=2009&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
#ifndef LL_LLTRANSLATE_H
#define LL_LLTRANSLATE_H
@@ -37,89 +31,273 @@
#include "llbufferstream.h"
#include "jsoncpp/reader.h"
-class LLTranslate
+namespace Json
{
-public :
- class TranslationReceiver: public LLHTTPClient::Responder
- {
- protected:
- TranslationReceiver(const std::string &fromLang, const std::string &toLang)
- : m_fromLang(fromLang),
- m_toLang(toLang)
- {
- }
+ class Value;
+}
- virtual void handleResponse(const std::string &translation, const std::string &recognizedLang) {}
- virtual void handleFailure() {};
+/**
+ * Handler of an HTTP machine translation service.
+ *
+ * Derived classes know the service URL
+ * and how to parse the translation result.
+ */
+class LLTranslationAPIHandler
+{
+public:
+ /**
+ * Get URL for translation of the given string.
+ *
+ * Sending HTTP GET request to the URL will initiate translation.
+ *
+ * @param[out] url Place holder for the result.
+ * @param from_lang Source language. Leave empty for auto-detection.
+ * @param to_lang Target language.
+ * @param text Text to translate.
+ */
+ virtual void getTranslateURL(
+ std::string &url,
+ const std::string &from_lang,
+ const std::string &to_lang,
+ const std::string &text) const = 0;
- public:
- ~TranslationReceiver()
- {
- }
+ /**
+ * Get URL to verify the given API key.
+ *
+ * Sending request to the URL verifies the key.
+ * Positive HTTP response (code 200) means that the key is valid.
+ *
+ * @param[out] url Place holder for the URL.
+ * @param[in] key Key to verify.
+ */
+ virtual void getKeyVerificationURL(
+ std::string &url,
+ const std::string &key) const = 0;
- virtual void error(U32 status, const std::string& reason)
- {
- LL_WARNS("Translate") << "URL Request error: " << reason << LL_ENDL;
- handleFailure();
- }
+ /**
+ * Parse translation response.
+ *
+ * @param[in,out] status HTTP status. May be modified while parsing.
+ * @param body Response text.
+ * @param[out] translation Translated text.
+ * @param[out] detected_lang Detected source language. May be empty.
+ * @param[out] err_msg Error message (in case of error).
+ */
+ virtual bool parseResponse(
+ int& status,
+ const std::string& body,
+ std::string& translation,
+ std::string& detected_lang,
+ std::string& err_msg) const = 0;
- virtual void completedRaw(
- U32 status,
- const std::string& reason,
- const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
- {
- LLBufferStream istr(channels, buffer.get());
+ /**
+ * @return if the handler is configured to function properly
+ */
+ virtual bool isConfigured() const = 0;
- std::stringstream strstrm;
- strstrm << istr.rdbuf();
- const std::string result = strstrm.str();
+ virtual ~LLTranslationAPIHandler() {}
- std::string translation;
- std::string detectedLanguage;
+protected:
+ static const int STATUS_OK = 200;
+};
- if (!parseGoogleTranslate(result, translation, detectedLanguage))
- {
- handleFailure();
- return;
- }
+/// Google Translate v2 API handler.
+class LLGoogleTranslationHandler : public LLTranslationAPIHandler
+{
+ LOG_CLASS(LLGoogleTranslationHandler);
- // Fix up the response
- stringReplaceAll( translation, "<","<");
- stringReplaceAll( translation, ">",">");
- stringReplaceAll( translation, ""","\"");
- stringReplaceAll( translation, "'","'");
- stringReplaceAll( translation, "&","&");
- stringReplaceAll( translation, "'","'");
-
- handleResponse(translation, detectedLanguage);
- }
-
- protected:
- const std::string m_toLang;
- const std::string m_fromLang;
- };
-
- static void translateMessage(LLHTTPClient::ResponderPtr &result, const std::string &fromLang, const std::string &toLang, const std::string &mesg);
- static float m_GoogleTimeout;
- static std::string getTranslateLanguage();
+public:
+ /*virtual*/ void getTranslateURL(
+ std::string &url,
+ const std::string &from_lang,
+ const std::string &to_lang,
+ const std::string &text) const;
+ /*virtual*/ void getKeyVerificationURL(
+ std::string &url,
+ const std::string &key) const;
+ /*virtual*/ bool parseResponse(
+ int& status,
+ const std::string& body,
+ std::string& translation,
+ std::string& detected_lang,
+ std::string& err_msg) const;
+ /*virtual*/ bool isConfigured() const;
private:
- static void getTranslateUrl(std::string &translateUrl, const std::string &fromLang, const std::string &toLang, const std::string &text);
- static void stringReplaceAll(std::string& context, const std::string& from, const std::string& to);
- static BOOL parseGoogleTranslate(const std::string result, std::string &translation, std::string &detectedLanguage);
+ static void parseErrorResponse(
+ const Json::Value& root,
+ int& status,
+ std::string& err_msg);
+ static bool parseTranslation(
+ const Json::Value& root,
+ std::string& translation,
+ std::string& detected_lang);
+ static std::string getAPIKey();
+};
- static LLSD m_Header;
- static const char* m_GoogleURL;
- static const char* m_GoogleLangSpec;
- static const char* m_AcceptHeader;
- static const char* m_AcceptType;
- static const char* m_AgentHeader;
- static const char* m_UserAgent;
+/// Microsoft Translator v2 API handler.
+class LLBingTranslationHandler : public LLTranslationAPIHandler
+{
+ LOG_CLASS(LLBingTranslationHandler);
- static const char* m_GoogleData;
- static const char* m_GoogleTranslation;
- static const char* m_GoogleLanguage;
+public:
+ /*virtual*/ void getTranslateURL(
+ std::string &url,
+ const std::string &from_lang,
+ const std::string &to_lang,
+ const std::string &text) const;
+ /*virtual*/ void getKeyVerificationURL(
+ std::string &url,
+ const std::string &key) const;
+ /*virtual*/ bool parseResponse(
+ int& status,
+ const std::string& body,
+ std::string& translation,
+ std::string& detected_lang,
+ std::string& err_msg) const;
+ /*virtual*/ bool isConfigured() const;
+private:
+ static std::string getAPIKey();
+};
+
+/**
+ * Entry point for machine translation services.
+ *
+ * Basically, to translate a string, we need to know the URL
+ * of a translation service, have a valid API for the service
+ * and be given the target language.
+ *
+ * Callers specify the string to translate and the target language,
+ * LLTranslate takes care of the rest.
+ *
+ * API keys for translation are taken from saved settings.
+ */
+class LLTranslate
+{
+ LOG_CLASS(LLTranslate);
+
+public :
+
+ typedef enum e_service {
+ SERVICE_BING,
+ SERVICE_GOOGLE,
+ } EService;
+
+ /**
+ * Subclasses are supposed to handle translation results (e.g. show them in chat)
+ */
+ class TranslationReceiver: public LLHTTPClient::Responder
+ {
+ public:
+
+ /**
+ * Using mHandler, parse incoming response.
+ *
+ * Calls either handleResponse() or handleFailure()
+ * depending on the HTTP status code and parsing success.
+ *
+ * @see handleResponse()
+ * @see handleFailure()
+ * @see mHandler
+ */
+ /*virtual*/ void completedRaw(
+ U32 http_status,
+ const std::string& reason,
+ const LLChannelDescriptors& channels,
+ const LLIOPipe::buffer_ptr_t& buffer);
+
+ protected:
+ friend class LLTranslate;
+
+ /// Remember source and target languages for subclasses to be able to filter inappropriate results.
+ TranslationReceiver(const std::string& from_lang, const std::string& to_lang);
+
+ /// Override point to handle successful translation.
+ virtual void handleResponse(const std::string &translation, const std::string &recognized_lang) = 0;
+
+ /// Override point to handle unsuccessful translation.
+ virtual void handleFailure(int status, const std::string& err_msg) = 0;
+
+ std::string mFromLang;
+ std::string mToLang;
+ const LLTranslationAPIHandler& mHandler;
+ };
+
+ /**
+ * Subclasses are supposed to handle API key verification result.
+ */
+ class KeyVerificationReceiver: public LLHTTPClient::Responder
+ {
+ public:
+ EService getService() const;
+
+ protected:
+ /**
+ * Save the translation service the key belongs to.
+ *
+ * Subclasses need to know it.
+ *
+ * @see getService()
+ */
+ KeyVerificationReceiver(EService service);
+
+ /**
+ * Parse verification response.
+ *
+ * Calls setVerificationStatus() with the verification status,
+ * which is true if HTTP status code is 200.
+ *
+ * @see setVerificationStatus()
+ */
+ /*virtual*/ void completedRaw(
+ U32 http_status,
+ const std::string& reason,
+ const LLChannelDescriptors& channels,
+ const LLIOPipe::buffer_ptr_t& buffer);
+
+ /**
+ * Override point for subclasses to handle key verification status.
+ */
+ virtual void setVerificationStatus(bool ok) = 0;
+
+ EService mService;
+ };
+
+ typedef boost::intrusive_ptr TranslationReceiverPtr;
+ typedef boost::intrusive_ptr KeyVerificationReceiverPtr;
+
+ /**
+ * Translate given text.
+ *
+ * @param receiver Object to pass translation result to.
+ * @param from_lang Source language. Leave empty for auto-detection.
+ * @param to_lang Target language.
+ * @param mesg Text to translate.
+ */
+ static void translateMessage(TranslationReceiverPtr &receiver, const std::string &from_lang, const std::string &to_lang, const std::string &mesg);
+
+ /**
+ * Verify given API key of a translation service.
+ *
+ * @param receiver Object to pass verification result to.
+ * @param key Key to verify.
+ */
+ static void verifyKey(KeyVerificationReceiverPtr& receiver, const std::string& key);
+
+ /**
+ * @return translation target language
+ */
+ static std::string getTranslateLanguage();
+
+ /**
+ * @return true if translation is configured properly.
+ */
+ static bool isTranslationConfigured();
+
+private:
+ static const LLTranslationAPIHandler& getPreferredHandler();
+ static const LLTranslationAPIHandler& getHandler(EService service);
+ static void sendRequest(const std::string& url, LLHTTPClient::ResponderPtr responder);
};
#endif
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 97ac3eb05..a060efd09 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -2957,23 +2957,23 @@ void process_decline_callingcard(LLMessageSystem* msg, void**)
class ChatTranslationReceiver : public LLTranslate::TranslationReceiver
{
public :
- ChatTranslationReceiver(const std::string &fromLang, const std::string &toLang, LLChat *chat,
+ ChatTranslationReceiver(const std::string &from_lang, const std::string &to_lang, LLChat *chat,
const BOOL history)
- : LLTranslate::TranslationReceiver(fromLang, toLang),
+ : LLTranslate::TranslationReceiver(from_lang, to_lang),
m_chat(chat),
m_history(history)
{
}
- static boost::intrusive_ptr build(const std::string &fromLang, const std::string &toLang, LLChat *chat, const BOOL history)
+ static boost::intrusive_ptr build(const std::string &from_lang, const std::string &to_lang, LLChat *chat, const BOOL history)
{
- return boost::intrusive_ptr(new ChatTranslationReceiver(fromLang, toLang, chat, history));
+ return boost::intrusive_ptr(new ChatTranslationReceiver(from_lang, to_lang, chat, history));
}
protected:
void handleResponse(const std::string &translation, const std::string &detectedLanguage)
{
- if (m_toLang != detectedLanguage)
+ if (mToLang != detectedLanguage)
m_chat->mText += " (" + translation + ")";
add_floater_chat(*m_chat, m_history);
@@ -2981,14 +2981,12 @@ protected:
delete m_chat;
}
- void handleFailure()
+ void handleFailure(int status, const std::string& err_msg)
{
- LLTranslate::TranslationReceiver::handleFailure();
+ llwarns << "Translation failed for mesg " << m_chat << " toLang " << mToLang << " fromLang " << mFromLang << llendl;
m_chat->mText += " (?)";
-
add_floater_chat(*m_chat, m_history);
-
delete m_chat;
}
@@ -3017,14 +3015,12 @@ void check_translate_chat(const std::string &mesg, LLChat &chat, const BOOL hist
if (translate && chat.mSourceType != CHAT_SOURCE_SYSTEM)
{
- // fromLang hardcoded to "" (autodetection) pending implementation of
- // SVC-4879
- const std::string &fromLang = "";
- const std::string &toLang = LLTranslate::getTranslateLanguage();
+ const std::string &from_lang = "";
+ const std::string &to_lang = LLTranslate::getTranslateLanguage();
LLChat *newChat = new LLChat(chat);
- LLHTTPClient::ResponderPtr result = ChatTranslationReceiver::build(fromLang, toLang, newChat, history);
- LLTranslate::translateMessage(result, fromLang, toLang, mesg);
+ LLTranslate::TranslationReceiverPtr result = ChatTranslationReceiver::build(from_lang, to_lang, newChat, history);
+ LLTranslate::translateMessage(result, from_lang, to_lang, mesg);
}
else
{
From 638832455215ff5710d3febf8825aee7c779d316 Mon Sep 17 00:00:00 2001
From: Drake Arconis
Date: Tue, 21 Feb 2012 09:27:10 -0500
Subject: [PATCH 6/9] Revert "This works for now. Need to do more testing."
This reverts commit c6d6eed7d33121ac2bbd466ac2e49cccd6f6d921.
---
indra/newview/app_settings/settings.xml | 54 +--
indra/newview/lltranslate.cpp | 465 +++++-------------------
indra/newview/lltranslate.h | 368 +++++--------------
indra/newview/llviewermessage.cpp | 26 +-
4 files changed, 221 insertions(+), 692 deletions(-)
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 7553e8816..2b521fed4 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -1,15 +1,16 @@
- Include
-
- settings_ascent.xml
- settings_ascent_coa.xml
- settings_sh.xml
- settings_rlv.xml
-
- SianaRenderDeferredInvisiprim
-
+ Include
+
+ settings_ascent.xml
+ settings_ascent_coa.xml
+ settings_sh.xml
+ settings_rlv.xml
+
+
+ SianaRenderDeferredInvisiprim
+
Comment
Support invisiprims in deferred mode
Persist
@@ -7524,45 +7525,12 @@
Comment
Translate incoming chat messages
Persist
- 1
+ 0
Type
Boolean
Value
0
- TranslationService
-
- Comment
- Translation API to use. (google|bing)
- Persist
- 1
- Type
- String
- Value
- bing
-
- GoogleTranslateAPIKey
-
- Comment
- Google Translate API key
- Persist
- 1
- Type
- String
- Value
-
-
- BingTranslateAPIKey
-
- Comment
- Bing AppID to use with the Microsoft Translator API
- Persist
- 1
- Type
- String
- Value
-
-
LastFeatureVersion
Comment
diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp
index fcff3a0c7..5a537ae95 100644
--- a/indra/newview/lltranslate.cpp
+++ b/indra/newview/lltranslate.cpp
@@ -2,401 +2,136 @@
* @file lltranslate.cpp
* @brief Functions for translating text via Google Translate.
*
- * $LicenseInfo:firstyear=2009&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, 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$
- */
+* $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 "llviewerprecompiledheaders.h"
-#include "lltranslate.h"
-
-#include
-
#include "llbufferstream.h"
-#include "lltrans.h"
+#include "lltranslate.h"
#include "llui.h"
-#include "llviewercontrol.h"
+#include "sgversion.h"
#include "llweb.h"
-#include "sgversion.h"
+//
+#include "llviewercontrol.h"
+//
-#include "jsoncpp/reader.h"
+// These two are concatenated with the language specifiers to form a complete Google Translate URL
+const char* LLTranslate::m_GoogleURL = "http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q=";
+const char* LLTranslate::m_GoogleLangSpec = "&langpair=";
+float LLTranslate::m_GoogleTimeout = 10;
-// virtual
-void LLGoogleTranslationHandler::getTranslateURL(
- std::string &url,
- const std::string &from_lang,
- const std::string &to_lang,
- const std::string &text) const
+LLSD LLTranslate::m_Header;
+// These constants are for the GET header.
+const char* LLTranslate::m_AcceptHeader = "Accept";
+const char* LLTranslate::m_AcceptType = "text/plain";
+const char* LLTranslate::m_AgentHeader = "User-Agent";
+
+// These constants are in the JSON returned from Google
+const char* LLTranslate::m_GoogleData = "responseData";
+const char* LLTranslate::m_GoogleTranslation = "translatedText";
+const char* LLTranslate::m_GoogleLanguage = "detectedSourceLanguage";
+
+//static
+void LLTranslate::translateMessage(LLHTTPClient::ResponderPtr &result, const std::string &fromLang, const std::string &toLang, const std::string &mesg)
{
- url = std::string("https://www.googleapis.com/language/translate/v2?key=")
- + getAPIKey() + "&q=" + LLURI::escape(text) + "&target=" + to_lang;
- if (!from_lang.empty())
+ std::string url;
+ getTranslateUrl(url, fromLang, toLang, mesg);
+
+//
+ std::string user_agent = gCurrentVersion;
+//
+
+ if (!m_Header.size())
{
- url += "&source=" + from_lang;
- }
-}
-
-// virtual
-void LLGoogleTranslationHandler::getKeyVerificationURL(
- std::string& url,
- const std::string& key) const
-{
- url = std::string("https://www.googleapis.com/language/translate/v2/languages?key=")
- + key + "&target=en";
-}
-
-// virtual
-bool LLGoogleTranslationHandler::parseResponse(
- int& status,
- const std::string& body,
- std::string& translation,
- std::string& detected_lang,
- std::string& err_msg) const
-{
- Json::Value root;
- Json::Reader reader;
-
- if (!reader.parse(body, root))
- {
- err_msg = reader.getFormatedErrorMessages();
- return false;
+ m_Header.insert(m_AcceptHeader, LLSD(m_AcceptType));
+ m_Header.insert(m_AgentHeader, LLSD(user_agent));
}
- if (!root.isObject()) // empty response? should not happen
- {
- return false;
- }
-
- if (status != STATUS_OK)
- {
- // Request failed. Extract error message from the response.
- parseErrorResponse(root, status, err_msg);
- return false;
- }
-
- // Request succeeded, extract translation from the response.
- return parseTranslation(root, translation, detected_lang);
-}
-
-// virtual
-bool LLGoogleTranslationHandler::isConfigured() const
-{
- return !getAPIKey().empty();
-}
-
-// static
-void LLGoogleTranslationHandler::parseErrorResponse(
- const Json::Value& root,
- int& status,
- std::string& err_msg)
-{
- const Json::Value& error = root.get("error", 0);
- if (!error.isObject() || !error.isMember("message") || !error.isMember("code"))
- {
- return;
- }
-
- err_msg = error["message"].asString();
- status = error["code"].asInt();
-}
-
-// static
-bool LLGoogleTranslationHandler::parseTranslation(
- const Json::Value& root,
- std::string& translation,
- std::string& detected_lang)
-{
- // JsonCpp is prone to aborting the program on failed assertions,
- // so be super-careful and verify the response format.
- const Json::Value& data = root.get("data", 0);
- if (!data.isObject() || !data.isMember("translations"))
- {
- return false;
- }
-
- const Json::Value& translations = data["translations"];
- if (!translations.isArray() || translations.size() == 0)
- {
- return false;
- }
-
- const Json::Value& first = translations[0U];
- if (!first.isObject() || !first.isMember("translatedText"))
- {
- return false;
- }
-
- translation = first["translatedText"].asString();
- detected_lang = first.get("detectedSourceLanguage", "").asString();
- return true;
-}
-
-// static
-std::string LLGoogleTranslationHandler::getAPIKey()
-{
- return gSavedSettings.getString("GoogleTranslateAPIKey");
-}
-
-// virtual
-void LLBingTranslationHandler::getTranslateURL(
- std::string &url,
- const std::string &from_lang,
- const std::string &to_lang,
- const std::string &text) const
-{
- url = std::string("http://api.microsofttranslator.com/v2/Http.svc/Translate?appId=")
- + getAPIKey() + "&text=" + LLURI::escape(text) + "&to=" + to_lang;
- if (!from_lang.empty())
- {
- url += "&from=" + from_lang;
- }
-}
-
-// virtual
-void LLBingTranslationHandler::getKeyVerificationURL(
- std::string& url,
- const std::string& key) const
-{
- url = std::string("http://api.microsofttranslator.com/v2/Http.svc/GetLanguagesForTranslate?appId=")
- + key;
-}
-
-// virtual
-bool LLBingTranslationHandler::parseResponse(
- int& status,
- const std::string& body,
- std::string& translation,
- std::string& detected_lang,
- std::string& err_msg) const
-{
- if (status != STATUS_OK)
- {
- static const std::string MSG_BEGIN_MARKER = "Message: ";
- size_t begin = body.find(MSG_BEGIN_MARKER);
- if (begin != std::string::npos)
- {
- begin += MSG_BEGIN_MARKER.size();
- }
- else
- {
- begin = 0;
- err_msg.clear();
- }
- size_t end = body.find("", begin);
- err_msg = body.substr(begin, end-begin);
- LLStringUtil::replaceString(err_msg, "
", ""); // strip CR
- return false;
- }
-
- // Sample response: Hola
- size_t begin = body.find(">");
- if (begin == std::string::npos || begin >= (body.size() - 1))
- {
- begin = 0;
- }
- else
- {
- ++begin;
- }
-
- size_t end = body.find("", begin);
-
- detected_lang = ""; // unsupported by this API
- translation = body.substr(begin, end-begin);
- LLStringUtil::replaceString(translation, "
", ""); // strip CR
- return true;
-}
-
-// virtual
-bool LLBingTranslationHandler::isConfigured() const
-{
- return !getAPIKey().empty();
-}
-
-// static
-std::string LLBingTranslationHandler::getAPIKey()
-{
- return gSavedSettings.getString("BingTranslateAPIKey");
-}
-
-LLTranslate::TranslationReceiver::TranslationReceiver(const std::string& from_lang, const std::string& to_lang)
-: mFromLang(from_lang)
-, mToLang(to_lang)
-, mHandler(LLTranslate::getPreferredHandler())
-{
-}
-
-// virtual
-void LLTranslate::TranslationReceiver::completedRaw(
- U32 http_status,
- const std::string& reason,
- const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
-{
- LLBufferStream istr(channels, buffer.get());
- std::stringstream strstrm;
- strstrm << istr.rdbuf();
-
- const std::string body = strstrm.str();
- std::string translation, detected_lang, err_msg;
- int status = http_status;
- LL_DEBUGS("Translate") << "HTTP status: " << status << " " << reason << LL_ENDL;
- LL_DEBUGS("Translate") << "Response body: " << body << LL_ENDL;
- if (mHandler.parseResponse(status, body, translation, detected_lang, err_msg))
- {
- // Fix up the response
- LLStringUtil::replaceString(translation, "<", "<");
- LLStringUtil::replaceString(translation, ">",">");
- LLStringUtil::replaceString(translation, ""","\"");
- LLStringUtil::replaceString(translation, "'","'");
- LLStringUtil::replaceString(translation, "&","&");
- LLStringUtil::replaceString(translation, "'","'");
-
- handleResponse(translation, detected_lang);
- }
- else
- {
- if (err_msg.empty())
- {
- err_msg = LLTrans::getString("TranslationResponseParseError");
- }
-
- llwarns << "Translation request failed: " << err_msg << llendl;
- handleFailure(status, err_msg);
- }
-}
-
-LLTranslate::KeyVerificationReceiver::KeyVerificationReceiver(EService service)
-: mService(service)
-{
-}
-
-LLTranslate::EService LLTranslate::KeyVerificationReceiver::getService() const
-{
- return mService;
-}
-
-// virtual
-void LLTranslate::KeyVerificationReceiver::completedRaw(
- U32 http_status,
- const std::string& reason,
- const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
-{
- bool ok = (http_status == 200);
- setVerificationStatus(ok);
+ LLHTTPClient::get(url, result, m_Header, m_GoogleTimeout);
}
//static
-void LLTranslate::translateMessage(
- TranslationReceiverPtr &receiver,
- const std::string &from_lang,
- const std::string &to_lang,
- const std::string &mesg)
+void LLTranslate::getTranslateUrl(std::string &translateUrl, const std::string &fromLang, const std::string &toLang, const std::string &mesg)
{
- std::string url;
- receiver->mHandler.getTranslateURL(url, from_lang, to_lang, mesg);
+ std::string escaped_mesg = LLWeb::curlEscape(mesg);
- LL_DEBUGS("Translate") << "Sending translation request: " << url << LL_ENDL;
- sendRequest(url, receiver);
+ translateUrl = m_GoogleURL
+ + escaped_mesg + m_GoogleLangSpec
+ + fromLang // 'from' language; empty string for auto
+ + "%7C" // |
+ + toLang; // 'to' language
}
-// static
-void LLTranslate::verifyKey(
- KeyVerificationReceiverPtr& receiver,
- const std::string& key)
+//static
+void LLTranslate::stringReplaceAll(std::string& context, const std::string& from, const std::string& to)
{
- std::string url;
- const LLTranslationAPIHandler& handler = getHandler(receiver->getService());
- handler.getKeyVerificationURL(url, key);
+ size_t lookHere = 0;
+ size_t foundHere;
- LL_DEBUGS("Translate") << "Sending key verification request: " << url << LL_ENDL;
- sendRequest(url, receiver);
+ while((foundHere = context.find(from, lookHere))
+ != std::string::npos) {
+ context.replace(foundHere, from.size(), to);
+ lookHere = foundHere + to.size();
+ }
+}
+
+//static
+BOOL LLTranslate::parseGoogleTranslate(const std::string result, std::string &translation, std::string &detectedLanguage)
+{
+ Json::Value root;
+ Json::Reader reader;
+ BOOL parsingSuccessful = reader.parse(result, root );
+ if ( !parsingSuccessful )
+ {
+ LL_WARNS("JSON") << reader.getFormatedErrorMessages() << LL_ENDL;
+ return FALSE;
+ }
+
+ translation = root[m_GoogleData].get(m_GoogleTranslation, "").asString();
+ detectedLanguage = root[m_GoogleData].get(m_GoogleLanguage, "").asString();
+ return TRUE;
}
//static
std::string LLTranslate::getTranslateLanguage()
{
- std::string language = gSavedSettings.getString("TranslateLanguage");
- if (language.empty() || language == "default")
+ std::string language = "en";
+ if (LLUI::sConfigGroup)
{
- language = LLUI::getLanguage();
+ language = LLUI::sConfigGroup->getString("TranslateLanguage");
+ if (language.empty() || language == "default")
+ {
+ language = LLUI::getLanguage();
+ }
}
language = language.substr(0,2);
return language;
}
-// static
-bool LLTranslate::isTranslationConfigured()
-{
- return getPreferredHandler().isConfigured();
-}
-
-// static
-const LLTranslationAPIHandler& LLTranslate::getPreferredHandler()
-{
- EService service = SERVICE_BING;
-
- std::string service_str = gSavedSettings.getString("TranslationService");
- if (service_str == "google")
- {
- service = SERVICE_GOOGLE;
- }
-
- return getHandler(service);
-}
-
-// static
-const LLTranslationAPIHandler& LLTranslate::getHandler(EService service)
-{
- static LLGoogleTranslationHandler google;
- static LLBingTranslationHandler bing;
-
- if (service == SERVICE_GOOGLE)
- {
- return google;
- }
-
- return bing;
-}
-
-// static
-void LLTranslate::sendRequest(const std::string& url, LLHTTPClient::ResponderPtr responder)
-{
- static const float REQUEST_TIMEOUT = 5;
- static LLSD sHeader;
-
- if (!sHeader.size())
- {
- std::string user_agent = llformat("%s %d.%d.%d (%d)",
- gVersionChannel,
- gVersionMajor,
- gVersionMinor,
- gVersionPatch,
- gVersionBuild);
-
- sHeader.insert("Accept", "text/plain");
- sHeader.insert("User-Agent", user_agent);
- }
-
- LLHTTPClient::get(url, responder, sHeader, REQUEST_TIMEOUT);
-}
diff --git a/indra/newview/lltranslate.h b/indra/newview/lltranslate.h
index 870cc1fae..2723c43ff 100644
--- a/indra/newview/lltranslate.h
+++ b/indra/newview/lltranslate.h
@@ -2,27 +2,33 @@
* @file lltranslate.h
* @brief Human language translation class and JSON response receiver.
*
- * $LicenseInfo:firstyear=2009&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, 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$
- */
+* $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_LLTRANSLATE_H
#define LL_LLTRANSLATE_H
@@ -31,273 +37,89 @@
#include "llbufferstream.h"
#include "jsoncpp/reader.h"
-namespace Json
-{
- class Value;
-}
-
-/**
- * Handler of an HTTP machine translation service.
- *
- * Derived classes know the service URL
- * and how to parse the translation result.
- */
-class LLTranslationAPIHandler
-{
-public:
- /**
- * Get URL for translation of the given string.
- *
- * Sending HTTP GET request to the URL will initiate translation.
- *
- * @param[out] url Place holder for the result.
- * @param from_lang Source language. Leave empty for auto-detection.
- * @param to_lang Target language.
- * @param text Text to translate.
- */
- virtual void getTranslateURL(
- std::string &url,
- const std::string &from_lang,
- const std::string &to_lang,
- const std::string &text) const = 0;
-
- /**
- * Get URL to verify the given API key.
- *
- * Sending request to the URL verifies the key.
- * Positive HTTP response (code 200) means that the key is valid.
- *
- * @param[out] url Place holder for the URL.
- * @param[in] key Key to verify.
- */
- virtual void getKeyVerificationURL(
- std::string &url,
- const std::string &key) const = 0;
-
- /**
- * Parse translation response.
- *
- * @param[in,out] status HTTP status. May be modified while parsing.
- * @param body Response text.
- * @param[out] translation Translated text.
- * @param[out] detected_lang Detected source language. May be empty.
- * @param[out] err_msg Error message (in case of error).
- */
- virtual bool parseResponse(
- int& status,
- const std::string& body,
- std::string& translation,
- std::string& detected_lang,
- std::string& err_msg) const = 0;
-
- /**
- * @return if the handler is configured to function properly
- */
- virtual bool isConfigured() const = 0;
-
- virtual ~LLTranslationAPIHandler() {}
-
-protected:
- static const int STATUS_OK = 200;
-};
-
-/// Google Translate v2 API handler.
-class LLGoogleTranslationHandler : public LLTranslationAPIHandler
-{
- LOG_CLASS(LLGoogleTranslationHandler);
-
-public:
- /*virtual*/ void getTranslateURL(
- std::string &url,
- const std::string &from_lang,
- const std::string &to_lang,
- const std::string &text) const;
- /*virtual*/ void getKeyVerificationURL(
- std::string &url,
- const std::string &key) const;
- /*virtual*/ bool parseResponse(
- int& status,
- const std::string& body,
- std::string& translation,
- std::string& detected_lang,
- std::string& err_msg) const;
- /*virtual*/ bool isConfigured() const;
-
-private:
- static void parseErrorResponse(
- const Json::Value& root,
- int& status,
- std::string& err_msg);
- static bool parseTranslation(
- const Json::Value& root,
- std::string& translation,
- std::string& detected_lang);
- static std::string getAPIKey();
-};
-
-/// Microsoft Translator v2 API handler.
-class LLBingTranslationHandler : public LLTranslationAPIHandler
-{
- LOG_CLASS(LLBingTranslationHandler);
-
-public:
- /*virtual*/ void getTranslateURL(
- std::string &url,
- const std::string &from_lang,
- const std::string &to_lang,
- const std::string &text) const;
- /*virtual*/ void getKeyVerificationURL(
- std::string &url,
- const std::string &key) const;
- /*virtual*/ bool parseResponse(
- int& status,
- const std::string& body,
- std::string& translation,
- std::string& detected_lang,
- std::string& err_msg) const;
- /*virtual*/ bool isConfigured() const;
-private:
- static std::string getAPIKey();
-};
-
-/**
- * Entry point for machine translation services.
- *
- * Basically, to translate a string, we need to know the URL
- * of a translation service, have a valid API for the service
- * and be given the target language.
- *
- * Callers specify the string to translate and the target language,
- * LLTranslate takes care of the rest.
- *
- * API keys for translation are taken from saved settings.
- */
class LLTranslate
{
- LOG_CLASS(LLTranslate);
-
public :
-
- typedef enum e_service {
- SERVICE_BING,
- SERVICE_GOOGLE,
- } EService;
-
- /**
- * Subclasses are supposed to handle translation results (e.g. show them in chat)
- */
class TranslationReceiver: public LLHTTPClient::Responder
{
- public:
+ protected:
+ TranslationReceiver(const std::string &fromLang, const std::string &toLang)
+ : m_fromLang(fromLang),
+ m_toLang(toLang)
+ {
+ }
- /**
- * Using mHandler, parse incoming response.
- *
- * Calls either handleResponse() or handleFailure()
- * depending on the HTTP status code and parsing success.
- *
- * @see handleResponse()
- * @see handleFailure()
- * @see mHandler
- */
- /*virtual*/ void completedRaw(
- U32 http_status,
+ virtual void handleResponse(const std::string &translation, const std::string &recognizedLang) {}
+ virtual void handleFailure() {};
+
+ public:
+ ~TranslationReceiver()
+ {
+ }
+
+ virtual void error(U32 status, const std::string& reason)
+ {
+ LL_WARNS("Translate") << "URL Request error: " << reason << LL_ENDL;
+ handleFailure();
+ }
+
+ virtual void completedRaw(
+ U32 status,
const std::string& reason,
const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer);
+ const LLIOPipe::buffer_ptr_t& buffer)
+ {
+ LLBufferStream istr(channels, buffer.get());
+
+ std::stringstream strstrm;
+ strstrm << istr.rdbuf();
+ const std::string result = strstrm.str();
+
+ std::string translation;
+ std::string detectedLanguage;
+
+ if (!parseGoogleTranslate(result, translation, detectedLanguage))
+ {
+ handleFailure();
+ return;
+ }
+
+ // Fix up the response
+ stringReplaceAll( translation, "<","<");
+ stringReplaceAll( translation, ">",">");
+ stringReplaceAll( translation, ""","\"");
+ stringReplaceAll( translation, "'","'");
+ stringReplaceAll( translation, "&","&");
+ stringReplaceAll( translation, "'","'");
+
+ handleResponse(translation, detectedLanguage);
+ }
protected:
- friend class LLTranslate;
-
- /// Remember source and target languages for subclasses to be able to filter inappropriate results.
- TranslationReceiver(const std::string& from_lang, const std::string& to_lang);
-
- /// Override point to handle successful translation.
- virtual void handleResponse(const std::string &translation, const std::string &recognized_lang) = 0;
-
- /// Override point to handle unsuccessful translation.
- virtual void handleFailure(int status, const std::string& err_msg) = 0;
-
- std::string mFromLang;
- std::string mToLang;
- const LLTranslationAPIHandler& mHandler;
+ const std::string m_toLang;
+ const std::string m_fromLang;
};
- /**
- * Subclasses are supposed to handle API key verification result.
- */
- class KeyVerificationReceiver: public LLHTTPClient::Responder
- {
- public:
- EService getService() const;
-
- protected:
- /**
- * Save the translation service the key belongs to.
- *
- * Subclasses need to know it.
- *
- * @see getService()
- */
- KeyVerificationReceiver(EService service);
-
- /**
- * Parse verification response.
- *
- * Calls setVerificationStatus() with the verification status,
- * which is true if HTTP status code is 200.
- *
- * @see setVerificationStatus()
- */
- /*virtual*/ void completedRaw(
- U32 http_status,
- const std::string& reason,
- const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer);
-
- /**
- * Override point for subclasses to handle key verification status.
- */
- virtual void setVerificationStatus(bool ok) = 0;
-
- EService mService;
- };
-
- typedef boost::intrusive_ptr TranslationReceiverPtr;
- typedef boost::intrusive_ptr KeyVerificationReceiverPtr;
-
- /**
- * Translate given text.
- *
- * @param receiver Object to pass translation result to.
- * @param from_lang Source language. Leave empty for auto-detection.
- * @param to_lang Target language.
- * @param mesg Text to translate.
- */
- static void translateMessage(TranslationReceiverPtr &receiver, const std::string &from_lang, const std::string &to_lang, const std::string &mesg);
-
- /**
- * Verify given API key of a translation service.
- *
- * @param receiver Object to pass verification result to.
- * @param key Key to verify.
- */
- static void verifyKey(KeyVerificationReceiverPtr& receiver, const std::string& key);
-
- /**
- * @return translation target language
- */
+ static void translateMessage(LLHTTPClient::ResponderPtr &result, const std::string &fromLang, const std::string &toLang, const std::string &mesg);
+ static float m_GoogleTimeout;
static std::string getTranslateLanguage();
- /**
- * @return true if translation is configured properly.
- */
- static bool isTranslationConfigured();
-
private:
- static const LLTranslationAPIHandler& getPreferredHandler();
- static const LLTranslationAPIHandler& getHandler(EService service);
- static void sendRequest(const std::string& url, LLHTTPClient::ResponderPtr responder);
+ static void getTranslateUrl(std::string &translateUrl, const std::string &fromLang, const std::string &toLang, const std::string &text);
+ static void stringReplaceAll(std::string& context, const std::string& from, const std::string& to);
+ static BOOL parseGoogleTranslate(const std::string result, std::string &translation, std::string &detectedLanguage);
+
+ static LLSD m_Header;
+ static const char* m_GoogleURL;
+ static const char* m_GoogleLangSpec;
+ static const char* m_AcceptHeader;
+ static const char* m_AcceptType;
+ static const char* m_AgentHeader;
+ static const char* m_UserAgent;
+
+ static const char* m_GoogleData;
+ static const char* m_GoogleTranslation;
+ static const char* m_GoogleLanguage;
};
#endif
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index a060efd09..97ac3eb05 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -2957,23 +2957,23 @@ void process_decline_callingcard(LLMessageSystem* msg, void**)
class ChatTranslationReceiver : public LLTranslate::TranslationReceiver
{
public :
- ChatTranslationReceiver(const std::string &from_lang, const std::string &to_lang, LLChat *chat,
+ ChatTranslationReceiver(const std::string &fromLang, const std::string &toLang, LLChat *chat,
const BOOL history)
- : LLTranslate::TranslationReceiver(from_lang, to_lang),
+ : LLTranslate::TranslationReceiver(fromLang, toLang),
m_chat(chat),
m_history(history)
{
}
- static boost::intrusive_ptr build(const std::string &from_lang, const std::string &to_lang, LLChat *chat, const BOOL history)
+ static boost::intrusive_ptr build(const std::string &fromLang, const std::string &toLang, LLChat *chat, const BOOL history)
{
- return boost::intrusive_ptr(new ChatTranslationReceiver(from_lang, to_lang, chat, history));
+ return boost::intrusive_ptr(new ChatTranslationReceiver(fromLang, toLang, chat, history));
}
protected:
void handleResponse(const std::string &translation, const std::string &detectedLanguage)
{
- if (mToLang != detectedLanguage)
+ if (m_toLang != detectedLanguage)
m_chat->mText += " (" + translation + ")";
add_floater_chat(*m_chat, m_history);
@@ -2981,12 +2981,14 @@ protected:
delete m_chat;
}
- void handleFailure(int status, const std::string& err_msg)
+ void handleFailure()
{
- llwarns << "Translation failed for mesg " << m_chat << " toLang " << mToLang << " fromLang " << mFromLang << llendl;
+ LLTranslate::TranslationReceiver::handleFailure();
m_chat->mText += " (?)";
+
add_floater_chat(*m_chat, m_history);
+
delete m_chat;
}
@@ -3015,12 +3017,14 @@ void check_translate_chat(const std::string &mesg, LLChat &chat, const BOOL hist
if (translate && chat.mSourceType != CHAT_SOURCE_SYSTEM)
{
- const std::string &from_lang = "";
- const std::string &to_lang = LLTranslate::getTranslateLanguage();
+ // fromLang hardcoded to "" (autodetection) pending implementation of
+ // SVC-4879
+ const std::string &fromLang = "";
+ const std::string &toLang = LLTranslate::getTranslateLanguage();
LLChat *newChat = new LLChat(chat);
- LLTranslate::TranslationReceiverPtr result = ChatTranslationReceiver::build(from_lang, to_lang, newChat, history);
- LLTranslate::translateMessage(result, from_lang, to_lang, mesg);
+ LLHTTPClient::ResponderPtr result = ChatTranslationReceiver::build(fromLang, toLang, newChat, history);
+ LLTranslate::translateMessage(result, fromLang, toLang, mesg);
}
else
{
From 803011582cb98435042cb534d44032977e33111c Mon Sep 17 00:00:00 2001
From: Drake Arconis
Date: Tue, 21 Feb 2012 10:53:47 -0500
Subject: [PATCH 7/9] Further OS X changes.
---
indra/cmake/Variables.cmake | 4 +--
indra/newview/CMakeLists.txt | 55 ++++++++++++++++++------------------
2 files changed, 30 insertions(+), 29 deletions(-)
diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake
index 964c9d684..0428ae87d 100644
--- a/indra/cmake/Variables.cmake
+++ b/indra/cmake/Variables.cmake
@@ -78,15 +78,15 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
#SDK Compiler and Deployment targets for XCode
if (${XCODE_VERSION} VERSION_LESS 4.0.0)
+ set(CMAKE_OSX_DEPLOYMENT_TARGET 10.5)
set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.5.sdk)
set(CMAKE_XCODE_ATTIBUTE_GCC_VERSION "4.2")
else (${XCODE_VERSION} VERSION_LESS 4.0.0)
+ set(CMAKE_OSX_DEPLOYMENT_TARGET 10.6)
set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.6.sdk)
set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION "com.apple.compilers.llvmgcc42")
endif (${XCODE_VERSION} VERSION_LESS 4.0.0)
- set(CMAKE_OSX_DEPLOYMENT_TARGET 10.5)
-
# NOTE: To attempt an i386/PPC Universal build, add this on the configure line:
# -DCMAKE_OSX_ARCHITECTURES:STRING='i386;ppc'
# Build only for i386 by default, system default on MacOSX 10.6 is x86_64
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 66b5b4b3a..014a63461 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -1338,39 +1338,40 @@ if (OPENAL)
endif (OPENAL)
if (FMOD OR FMODEX)
- if(FMODEX)
- set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMODEX")
- endif(FMODEX)
- if(FMOD)
+ if (FMODEX)
+ set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMODEX")
+ endif (FMODEX)
+ if (FMOD)
set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMOD")
- endif(FMOD)
+ endif (FMOD)
- if (NOT WINDOWS)
+ if (DARWIN)
set(fmodwrapper_SOURCE_FILES fmodwrapper.cpp)
add_library(fmodwrapper SHARED ${fmodwrapper_SOURCE_FILES})
- if(FMOD AND FMODEX)
- set(fmodwrapper_needed_LIBRARIES "${FMODEX_LIBRARY} ${FMOD_LIBRARY}")
- else(FMOD AND FMODEX)
- if(FMODEX)
- set(fmodwrapper_needed_LIBRARIES ${FMODEX_LIBRARY})
- endif(FMODEX)
- if(FMOD)
- set(fmodwrapper_needed_LIBRARIES "${FMOD_LIBRARY}")
- endif(FMOD)
- endif(FMOD AND FMODEX)
- if (DARWIN)
- list(APPEND fmodwrapper_needed_LIBRARIES ${CARBON_LIBRARY})
- set_target_properties(
- fmodwrapper
- PROPERTIES
- BUILD_WITH_INSTALL_RPATH 1
- INSTALL_NAME_DIR "@executable_path/../Resources"
- LINK_FLAGS "-unexported_symbols_list \"${CMAKE_CURRENT_SOURCE_DIR}/fmod_hidden_symbols.exp\""
- )
- endif (DARWIN)
+ if (FMODEX)
+ set(fmodwrapper_needed_LIBRARIES ${FMODEX_LIBRARY} ${CARBON_LIBRARY})
+ endif (FMODEX)
+ if (FMOD)
+ set(fmodwrapper_needed_LIBRARIES ${FMOD_LIBRARY} ${CARBON_LIBRARY})
+ endif (FMOD)
+ set_target_properties(
+ fmodwrapper
+ PROPERTIES
+ BUILD_WITH_INSTALL_RPATH 1
+ INSTALL_NAME_DIR "@executable_path/../Resources"
+ LINK_FLAGS "-unexported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/fmod_hidden_symbols.exp"
+ )
set(FMODWRAPPER_LIBRARY fmodwrapper)
target_link_libraries(fmodwrapper ${fmodwrapper_needed_LIBRARIES})
- endif (NOT WINDOWS)
+ else (DARWIN)
+ # fmodwrapper unnecessary on linux or windows, for fmod and fmodex
+ if (FMODEX)
+ set(FMODWRAPPER_LIBRARY ${FMODEX_LIBRARY})
+ endif (FMODEX)
+ if (FMOD)
+ set(FMODWRAPPER_LIBRARY ${FMOD_LIBRARY})
+ endif (FMOD)
+ endif (DARWIN)
endif (FMOD OR FMODEX)
set_source_files_properties(llstartup.cpp PROPERTIES COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS}")
From 3250725aaec50444a1ef85a956291b224bcd3d3e Mon Sep 17 00:00:00 2001
From: Drake Arconis
Date: Tue, 21 Feb 2012 10:56:27 -0500
Subject: [PATCH 8/9] Annoying Crash Fix.
This fixes that thing where saving scripts in deleted object makes
viewer go FFFFFF.
---
indra/newview/llpreviewscript.cpp | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp
index 6682a6e8c..b4b8ef4d2 100644
--- a/indra/newview/llpreviewscript.cpp
+++ b/indra/newview/llpreviewscript.cpp
@@ -2301,6 +2301,13 @@ void LLLiveLSLEditor::saveIfNeeded()
return;
}
+// [RLVa:KB] - Checked: 2010-11-25 (RLVa-1.2.2b) | Modified: RLVa-1.2.2b
+ if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachment(object->getRootEdit())) )
+ {
+ return;
+ }
+// [/RLVa:KB]
+
// get the latest info about it. We used to be losing the script
// name on save, because the viewer object version of the item,
// and the editor version would get out of synch. Here's a good
@@ -2607,14 +2614,6 @@ void LLLiveLSLEditor::onSave(void* userdata, BOOL close_after_save)
{
LLLiveLSLEditor* self = (LLLiveLSLEditor*)userdata;
-// [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.0.5a
- const LLViewerObject* pObject = gObjectList.findObject(self->mObjectID);
- if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachment(pObject->getRootEdit())) )
- {
- return;
- }
-// [/RLVa:KB]
-
self->mCloseAfterSave = close_after_save;
self->saveIfNeeded();
}
From edbc22961e197bed9c0840b3527736e9fbd89960 Mon Sep 17 00:00:00 2001
From: Drake Arconis
Date: Wed, 22 Feb 2012 05:49:38 -0500
Subject: [PATCH 9/9] Revert "Further OS X changes."
This reverts commit 803011582cb98435042cb534d44032977e33111c.
---
indra/cmake/Variables.cmake | 4 +--
indra/newview/CMakeLists.txt | 55 ++++++++++++++++++------------------
2 files changed, 29 insertions(+), 30 deletions(-)
diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake
index 0428ae87d..964c9d684 100644
--- a/indra/cmake/Variables.cmake
+++ b/indra/cmake/Variables.cmake
@@ -78,15 +78,15 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
#SDK Compiler and Deployment targets for XCode
if (${XCODE_VERSION} VERSION_LESS 4.0.0)
- set(CMAKE_OSX_DEPLOYMENT_TARGET 10.5)
set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.5.sdk)
set(CMAKE_XCODE_ATTIBUTE_GCC_VERSION "4.2")
else (${XCODE_VERSION} VERSION_LESS 4.0.0)
- set(CMAKE_OSX_DEPLOYMENT_TARGET 10.6)
set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.6.sdk)
set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION "com.apple.compilers.llvmgcc42")
endif (${XCODE_VERSION} VERSION_LESS 4.0.0)
+ set(CMAKE_OSX_DEPLOYMENT_TARGET 10.5)
+
# NOTE: To attempt an i386/PPC Universal build, add this on the configure line:
# -DCMAKE_OSX_ARCHITECTURES:STRING='i386;ppc'
# Build only for i386 by default, system default on MacOSX 10.6 is x86_64
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 014a63461..66b5b4b3a 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -1338,40 +1338,39 @@ if (OPENAL)
endif (OPENAL)
if (FMOD OR FMODEX)
- if (FMODEX)
- set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMODEX")
- endif (FMODEX)
- if (FMOD)
+ if(FMODEX)
+ set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMODEX")
+ endif(FMODEX)
+ if(FMOD)
set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMOD")
- endif (FMOD)
+ endif(FMOD)
- if (DARWIN)
+ if (NOT WINDOWS)
set(fmodwrapper_SOURCE_FILES fmodwrapper.cpp)
add_library(fmodwrapper SHARED ${fmodwrapper_SOURCE_FILES})
- if (FMODEX)
- set(fmodwrapper_needed_LIBRARIES ${FMODEX_LIBRARY} ${CARBON_LIBRARY})
- endif (FMODEX)
- if (FMOD)
- set(fmodwrapper_needed_LIBRARIES ${FMOD_LIBRARY} ${CARBON_LIBRARY})
- endif (FMOD)
- set_target_properties(
- fmodwrapper
- PROPERTIES
- BUILD_WITH_INSTALL_RPATH 1
- INSTALL_NAME_DIR "@executable_path/../Resources"
- LINK_FLAGS "-unexported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/fmod_hidden_symbols.exp"
- )
+ if(FMOD AND FMODEX)
+ set(fmodwrapper_needed_LIBRARIES "${FMODEX_LIBRARY} ${FMOD_LIBRARY}")
+ else(FMOD AND FMODEX)
+ if(FMODEX)
+ set(fmodwrapper_needed_LIBRARIES ${FMODEX_LIBRARY})
+ endif(FMODEX)
+ if(FMOD)
+ set(fmodwrapper_needed_LIBRARIES "${FMOD_LIBRARY}")
+ endif(FMOD)
+ endif(FMOD AND FMODEX)
+ if (DARWIN)
+ list(APPEND fmodwrapper_needed_LIBRARIES ${CARBON_LIBRARY})
+ set_target_properties(
+ fmodwrapper
+ PROPERTIES
+ BUILD_WITH_INSTALL_RPATH 1
+ INSTALL_NAME_DIR "@executable_path/../Resources"
+ LINK_FLAGS "-unexported_symbols_list \"${CMAKE_CURRENT_SOURCE_DIR}/fmod_hidden_symbols.exp\""
+ )
+ endif (DARWIN)
set(FMODWRAPPER_LIBRARY fmodwrapper)
target_link_libraries(fmodwrapper ${fmodwrapper_needed_LIBRARIES})
- else (DARWIN)
- # fmodwrapper unnecessary on linux or windows, for fmod and fmodex
- if (FMODEX)
- set(FMODWRAPPER_LIBRARY ${FMODEX_LIBRARY})
- endif (FMODEX)
- if (FMOD)
- set(FMODWRAPPER_LIBRARY ${FMOD_LIBRARY})
- endif (FMOD)
- endif (DARWIN)
+ endif (NOT WINDOWS)
endif (FMOD OR FMODEX)
set_source_files_properties(llstartup.cpp PROPERTIES COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS}")