summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
Diffstat (limited to 'indra')
-rw-r--r--indra/CMakeLists.txt1
-rw-r--r--indra/appearance_utility/CMakeLists.txt54
-rw-r--r--indra/appearance_utility/appearance_utility.cpp429
-rwxr-xr-xindra/appearance_utility/wrapper.sh25
4 files changed, 509 insertions, 0 deletions
diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt
index 078b17bf53..4e209ff75a 100644
--- a/indra/CMakeLists.txt
+++ b/indra/CMakeLists.txt
@@ -83,6 +83,7 @@ if (VIEWER)
if (LINUX)
add_subdirectory(${VIEWER_PREFIX}linux_crash_logger)
add_subdirectory(${VIEWER_PREFIX}linux_updater)
+ add_subdirectory(${VIEWER_PREFIX}appearance_utility)
add_dependencies(viewer linux-crash-logger-strip-target linux-updater)
elseif (DARWIN)
add_subdirectory(${VIEWER_PREFIX}mac_crash_logger)
diff --git a/indra/appearance_utility/CMakeLists.txt b/indra/appearance_utility/CMakeLists.txt
new file mode 100644
index 0000000000..c38f811b44
--- /dev/null
+++ b/indra/appearance_utility/CMakeLists.txt
@@ -0,0 +1,54 @@
+# -*- cmake -*-
+
+project(appearance_utility)
+
+include(00-Common)
+include(CURL)
+include(CARes)
+include(OpenSSL)
+include(UI)
+include(LLAppearance)
+include(LLCommon)
+include(LLVFS)
+include(LLXML)
+include(LLUI)
+include(Linking)
+
+include_directories(
+ ${LLCOMMON_INCLUDE_DIRS}
+ ${LLVFS_INCLUDE_DIRS}
+ ${LLXML_INCLUDE_DIRS}
+ ${LLUI_INCLUDE_DIRS}
+ ${CURL_INCLUDE_DIRS}
+ ${CARES_INCLUDE_DIRS}
+ ${OPENSSL_INCLUDE_DIRS}
+ ${UI_INCLUDE_DIRS}
+ ${LLAPPEARANCE_INCLUDE_DIRS}
+ )
+
+set(appearance_utility_SOURCE_FILES appearance_utility.cpp)
+
+set(appearance_utility_HEADER_FILES CMakeLists.txt)
+
+set_source_files_properties(${appearance_utility_HEADER_FILES}
+ PROPERTIES HEADER_FILES_ONLY TRUE)
+
+list(APPEND appearance_utility_SOURCE_FILES ${appearance_utility_HEADER_FILES})
+
+add_executable(appearance-utility-bin ${appearance_utility_SOURCE_FILES})
+
+target_link_libraries(appearance-utility-bin
+ ${CURL_LIBRARIES}
+ ${CARES_LIBRARIES}
+ ${OPENSSL_LIBRARIES}
+ ${CRYPTO_LIBRARIES}
+ ${UI_LIBRARIES}
+ ${LLAPPEARANCE_LIBRARIES}
+ ${LLXML_LIBRARIES}
+ ${LLUI_LIBRARIES}
+ ${LLVFS_LIBRARIES}
+ ${LLCOMMON_LIBRARIES}
+ )
+
+add_custom_target(appearance-utility-bin-target ALL
+ DEPENDS appearance-utility-bin)
diff --git a/indra/appearance_utility/appearance_utility.cpp b/indra/appearance_utility/appearance_utility.cpp
new file mode 100644
index 0000000000..130bca84a8
--- /dev/null
+++ b/indra/appearance_utility/appearance_utility.cpp
@@ -0,0 +1,429 @@
+/**
+ * @file appearance_utility.cpp
+ * @author Don Kjer <don@lindenlab.com>, Nyx Linden
+ * @brief Utility for processing avatar appearance without a full viewer implementation.
+ *
+ * $LicenseInfo:firstyear=2012&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, 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 <iostream>
+#include <sstream>
+#include <string>
+
+#include "linden_common.h"
+
+#include "llapp.h"
+#include "llapr.h"
+#include "llerrorcontrol.h"
+#include "llsd.h"
+#include "llsdserialize.h"
+#include "llsdutil.h"
+
+enum EResult
+{
+ RV_SUCCESS = 0,
+ RV_UNKNOWN_ERROR,
+ RV_BAD_ARGUMENTS,
+ RV_UNABLE_OPEN,
+ RV_UNABLE_TO_PARSE,
+};
+
+static const std::string MESSAGE_RV_UNKNOWN("Unknown error.");
+static const std::string MESSAGE_RV_ARGUMENTS
+("Invalid arguments: ");
+static const std::string MESSAGE_RV_UNABLE_OPEN("Unable to open file: ");
+static const std::string MESSAGE_RV_UNABLE_TO_PARSE("Unable to parse input LLSD.");
+
+static const apr_getopt_option_t APPEARANCE_UTILITY_OPTIONS[] =
+{
+ {"tbd", 't', 0, "Extract dump information from a mesh asset."},
+ {"output", 'o', 1, "The output file to write to. Default is stdout"},
+ {"agent-id", 'a', 1, "The agent-id of the user."},
+ {"grid", 'g', 1, "The grid."},
+ {"help", 'h', 0, "Print the help message."},
+ {0, 0, 0, 0}
+};
+
+const std::string NOTHING_EXTRA("");
+
+/**
+ * Helper to return the standard error based on the return value.
+ */
+LLSD spit_error(EResult rv, const std::string& extra = NOTHING_EXTRA);
+
+/**
+ * Helper to generate an error output based on code and message.
+ */
+LLSD spit_error(const std::string& key, const std::string& message);
+
+
+
+LLSD spit_error(EResult value, const std::string& extra)
+{
+ LLSD rv;
+ switch(value)
+ {
+ case RV_UNKNOWN_ERROR:
+ rv = spit_error("unknown", MESSAGE_RV_UNKNOWN);
+ case RV_BAD_ARGUMENTS:
+ rv = spit_error("arguments", MESSAGE_RV_ARGUMENTS + extra);
+ break;
+ case RV_UNABLE_OPEN:
+ rv = spit_error("file", MESSAGE_RV_UNABLE_OPEN + extra);
+ break;
+ case RV_UNABLE_TO_PARSE:
+ rv = spit_error("input", MESSAGE_RV_UNABLE_TO_PARSE);
+ break;
+ default:
+ rv = spit_error("arguments", "Invalid arguments to spit_error");
+ break;
+ }
+ return rv;
+}
+
+LLSD spit_error(const std::string& key, const std::string& message)
+{
+ LLSD rv;
+ rv["success"] = false;
+ rv["error"]["key"] = key;
+ rv["error"]["message"] = message;
+ return rv;
+}
+
+
+std::string usage(const char* command)
+{
+ std::ostringstream ostr;
+ ostr << "Utilities for processing agent appearance data."
+ << std::endl << std::endl
+ << "Usage:" << std::endl
+ << "\t" << command << " [options] filename" << std::endl << std::endl
+ << "Will read from stdin if filename is set to '-'." << std::endl << std::endl
+ << "Options:" << std::endl;
+ const apr_getopt_option_t* option = &APPEARANCE_UTILITY_OPTIONS[0];
+ while(option->name)
+ {
+ ostr << "\t--" << option->name << "\t\t"
+ << option->description << std::endl;
+ ++option;
+ }
+ ostr << std::endl << "Return Values:" << std::endl
+ << "\t0\t\tSuccess." << std::endl
+ << "\t1\t\tUnknown error." << std::endl
+ << "\t2\t\tBad arguments." << std::endl
+ << "\t3\t\tUnable to open file. Possibly wrong filename"
+ << " or bad permissions." << std::endl
+ << "\t4\t\tUnable to parse input LLSD." << std::endl
+ << std::endl
+ << "Output:" << std::endl
+ << "If a non-zero status code is returned, additional error information"
+ << " will be returned on stderr." << std::endl
+ << "* This will be in the form of an LLSD document." << std::endl
+ << "* Check ['error']['message'] to get a human readable message." << std::endl
+ << "If a zero status code is returned, processed output will be written"
+ << " to the file specified by --out (or stdout, if not specified)." << std::endl
+ << std::endl
+ << std::endl;
+ return ostr.str();
+}
+
+EResult process_tbd(LLSD& input, std::ostream& output, LLSD& error_llsd)
+{
+ EResult rv = RV_SUCCESS;
+
+ LLSD result;
+ result["success"] = true;
+ result["input"] = input;
+ output << LLSDOStreamer<LLSDXMLFormatter>(result);
+
+ return rv;
+}
+
+/**
+ * @brief Called by main() to ensure proper cleanup. Basically main().
+ */
+EResult process_command(int argc, char** argv, LLSD& error_llsd)
+{
+ EResult rv = RV_SUCCESS;
+
+ ////// BEGIN OPTION PARSING //////
+ // Check for '-' as last option, since apr doesn't seem to like that.
+ bool read_stdin = false;
+ bool write_stdout = true;
+ if (std::string(argv[argc-1]) == "-")
+ {
+ read_stdin = true;
+ argc--;
+ }
+
+ apr_status_t apr_err;
+ const char* opt_arg = NULL;
+ int opt_id = 0;
+ apr_getopt_t* os = NULL;
+ if(APR_SUCCESS != apr_getopt_init(&os, gAPRPoolp, argc, argv))
+ {
+ std::cerr << "Unable to initialize apr" << std::endl;
+ rv = RV_UNKNOWN_ERROR;
+ error_llsd = spit_error(rv);
+ return rv;
+ }
+
+ bool tbd = false;
+ LLUUID agent_id;
+ std::string output_filename;
+ std::string grid;
+ while(true)
+ {
+ apr_err = apr_getopt_long(os, APPEARANCE_UTILITY_OPTIONS, &opt_id, &opt_arg);
+ if(APR_STATUS_IS_EOF(apr_err)) break;
+ if(apr_err)
+ {
+ char buf[MAX_STRING]; /* Flawfinder: ignore */
+ std::cerr << "Error parsing options: "
+ << apr_strerror(apr_err, buf, MAX_STRING) << std::endl;
+ std::cerr << usage(os->argv[0]) << std::endl;
+ rv = RV_BAD_ARGUMENTS;
+ error_llsd = spit_error(rv, buf);
+ return rv;
+ }
+ switch (opt_id)
+ {
+ case 't':
+ tbd = true;
+ break;
+ case 'o':
+ output_filename.assign(opt_arg);
+ write_stdout=false;
+ break;
+ case 'a':
+ agent_id.set(opt_arg);
+ if (agent_id.isNull())
+ {
+ const char* INVALID_AGENT_ID="agent-id must be a valid uuid.";
+ std::cerr << "Incorrect arguments. " << INVALID_AGENT_ID
+ << std::endl << usage(argv[0]) << std::endl;
+ rv = RV_BAD_ARGUMENTS;
+ error_llsd = spit_error(rv, INVALID_AGENT_ID);
+ return rv;
+ }
+ break;
+ case 'g':
+ grid = opt_arg;
+ break;
+ case 'h':
+ std::cout << usage(os->argv[0]);
+ return RV_SUCCESS;
+ default:
+ std::cerr << usage(os->argv[0]);
+ rv = RV_BAD_ARGUMENTS;
+ error_llsd = spit_error(rv, "Unknown option.");
+ return rv;
+ }
+ }
+ ////// END OPTION PARSING //////
+
+ ///// BEGIN ARGUMENT VALIDATION /////
+ std::string input_filename;
+
+ // Make sure we don't have more than one command specified.
+ if (!tbd)
+ {
+ const char* INVALID_MODE="Must specify mode. (tbd)";
+ std::cerr << "Incorrect arguments. " << INVALID_MODE
+ << std::endl;
+ std::cerr << usage(os->argv[0]);
+ rv = RV_BAD_ARGUMENTS;
+ error_llsd = spit_error(rv, INVALID_MODE);
+ return rv;
+ }
+
+ // *TODO: Add debug mode(s). Skip this in debug mode.
+ LLError::setDefaultLevel(LLError::LEVEL_WARN);
+
+ if (!read_stdin)
+ {
+ bool valid_input_filename = false;
+ // Try to grab the input filename.
+ if (os->argv && os->argv[os->ind])
+ {
+ input_filename.assign(os->argv[os->ind]);
+ if (! input_filename.empty() )
+ {
+ valid_input_filename = true;
+ }
+ }
+ if (!valid_input_filename)
+ {
+ const char* INVALID_FILENAME="Must specify input file.";
+ std::cerr << "Incorrect arguments. " << INVALID_FILENAME
+ << std::endl << usage(os->argv[0]) << std::endl;
+ rv = RV_BAD_ARGUMENTS;
+ error_llsd = spit_error(rv, INVALID_FILENAME);
+ return rv;
+ }
+ }
+
+ ///// END ARGUMENT VALIDATION /////
+
+ ///// BEGIN OPEN INPUT FILE ////
+ std::ifstream input_file;
+ std::stringstream data;
+ std::istream* input = NULL;
+
+ if (read_stdin)
+ {
+ // Read unformated data from stdin in to memory.
+ const S32 BUFFER_SIZE = BUFSIZ;
+ char buffer[BUFFER_SIZE];
+ while (true)
+ {
+ std::cin.read(buffer, BUFFER_SIZE);
+ // Check if anything out of the ordinary happened.
+ if (!std::cin)
+ {
+ // See if something 'really bad' happened, or if we just
+ // used up all of our buffer.
+ if (std::cin.bad())
+ {
+ std::cerr << "Problem reading standard input." << std::endl;
+ rv = RV_UNKNOWN_ERROR;
+ error_llsd = spit_error(rv);
+ return rv;
+ }
+ else
+ {
+ // Output normally.
+ data.write(buffer, std::cin.gcount());
+ if (std::cin.eof()) break;
+
+ // Clear this problem. We have handled it.
+ std::cin.clear();
+ }
+ }
+ else
+ {
+ data.write(buffer, std::cin.gcount());
+ if (std::cin.eof()) break;
+ }
+ }
+ input = &data;
+ }
+ else
+ {
+ // Make sure we can open the input file.
+ input_file.open( input_filename.c_str(), std::fstream::in );
+ if ( input_file.fail())
+ {
+ std::cerr << "Couldn't open input file '" << input_filename << "'." << std::endl;
+ rv = RV_UNABLE_OPEN;
+ error_llsd = spit_error(rv, input_filename);
+ return rv;
+ }
+ input = &input_file;
+ }
+ ///// END OPEN INPUT FILE ////
+
+ ///// BEGIN OPEN OUTPUT FILE ////
+ std::fstream output_file;
+ std::ostream* output = NULL;
+
+ // Make sure we can open the output file.
+ if (write_stdout)
+ {
+ output = &std::cout;
+ }
+ else
+ {
+ output_file.open( output_filename.c_str(), std::fstream::out );
+ if ( output_file.fail() )
+ {
+ std::cerr << "Couldn't open output file '" << output_filename << "'." << std::endl;
+ rv = RV_UNABLE_OPEN;
+ error_llsd = spit_error(rv, output_filename);
+ if (!read_stdin) input_file.close();
+ return rv;
+ }
+ output = &output_file;
+ }
+ ///// END OPEN OUTPUT FILE ////
+
+ ///// BEGIN INPUT PARSING ////
+ LLSD input_llsd;
+ LLSDSerialize::fromXML( input_llsd, *input );
+ if (input_llsd.isUndefined())
+ {
+ rv = RV_UNABLE_TO_PARSE;
+ error_llsd = spit_error(rv);
+ return rv;
+ }
+
+ ///// END INPUT PARSING ////
+
+ if (tbd)
+ {
+ rv = process_tbd(input_llsd, *output, error_llsd);
+ }
+
+ if (!write_stdout) output_file.close();
+ if (!read_stdin) input_file.close();
+
+ return rv;
+}
+
+class LLAppAppearanceUtility : public LLApp
+{
+public:
+ LLAppAppearanceUtility() {}
+ virtual ~LLAppAppearanceUtility() {}
+ /*virtual*/ bool init();
+ /*virtual*/ bool cleanup();
+ /*virtual*/ bool mainLoop() { return true;}
+};
+
+bool LLAppAppearanceUtility::init()
+{
+ return true;
+}
+
+bool LLAppAppearanceUtility::cleanup()
+{
+ return true;
+}
+
+int main(int argc, char** argv)
+{
+ ll_init_apr();
+ LLAppAppearanceUtility* app = new LLAppAppearanceUtility();
+ app->init();
+ LLSD error_llsd;
+ EResult rv = process_command(argc, argv, error_llsd);
+ if (RV_SUCCESS != rv)
+ {
+ std::cerr << LLSDOStreamer<LLSDXMLFormatter>(error_llsd);
+ }
+ app->cleanup();
+ delete app;
+ ll_cleanup_apr();
+ return (int) rv;
+}
+
+
diff --git a/indra/appearance_utility/wrapper.sh b/indra/appearance_utility/wrapper.sh
new file mode 100755
index 0000000000..87d2179a13
--- /dev/null
+++ b/indra/appearance_utility/wrapper.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+# Simple wrapper for secondlife utilities.
+
+## - Avoids an often-buggy X feature that doesn't really benefit us anyway.
+export SDL_VIDEO_X11_DGAMOUSE=0
+
+## - Works around a problem with misconfigured 64-bit systems not finding GL
+export LIBGL_DRIVERS_PATH="${LIBGL_DRIVERS_PATH}":/usr/lib64/dri:/usr/lib32/dri:/usr/lib/dri
+
+## - The 'scim' GTK IM module widely crashes the viewer. Avoid it.
+if [ "$GTK_IM_MODULE" = "scim" ]; then
+ export GTK_IM_MODULE=xim
+fi
+
+EXECUTABLE="$(basename "$0")-bin"
+SCRIPTSRC="$(readlink -f "$0" || echo "$0")"
+RUN_PATH="$(dirname "${SCRIPTSRC}" || echo .)"
+cd "${RUN_PATH}"
+
+export LD_LIBRARY_PATH="$PWD/lib:${LD_LIBRARY_PATH}"
+
+# Run the program.
+"./$EXECUTABLE" "$@"
+exit $?