diff options
| -rw-r--r-- | indra/appearance_utility/appearance_utility.cpp | 396 | 
1 files changed, 394 insertions, 2 deletions
| diff --git a/indra/appearance_utility/appearance_utility.cpp b/indra/appearance_utility/appearance_utility.cpp index 62b1cfd237..130bca84a8 100644 --- a/indra/appearance_utility/appearance_utility.cpp +++ b/indra/appearance_utility/appearance_utility.cpp @@ -25,13 +25,405 @@   * $/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)  { -	printf("Test app\n"); -	return 0; +	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;  } | 
