Merge branch 'master' of git://github.com/AlericInglewood/SingularityViewer
This commit is contained in:
@@ -117,7 +117,8 @@ public:
|
||||
/*virtual*/ void stopAnimating(BOOL upload_bake);
|
||||
/*virtual*/ BOOL linkDrivenParams(visual_param_mapper mapper, BOOL only_cross_params);
|
||||
/*virtual*/ void resetDrivenParams();
|
||||
|
||||
/*virtual*/ char const* getTypeString(void) const { return "param_driver"; }
|
||||
|
||||
// LLViewerVisualParam Virtual functions
|
||||
/*virtual*/ F32 getTotalDistortion();
|
||||
/*virtual*/ const LLVector4a& getAvgDistortion();
|
||||
|
||||
@@ -173,6 +173,7 @@ public:
|
||||
// LLVisualParam Virtual functions
|
||||
///*virtual*/ BOOL parseData(LLXmlTreeNode* node);
|
||||
/*virtual*/ void apply( ESex sex );
|
||||
/*virtual*/ char const* getTypeString(void) const { return "param_morph"; }
|
||||
|
||||
// LLViewerVisualParam Virtual functions
|
||||
/*virtual*/ F32 getTotalDistortion();
|
||||
|
||||
@@ -109,7 +109,8 @@ public:
|
||||
// LLVisualParam Virtual functions
|
||||
///*virtual*/ BOOL parseData(LLXmlTreeNode* node);
|
||||
/*virtual*/ void apply( ESex sex );
|
||||
|
||||
/*virtual*/ char const* getTypeString(void) const { return "param_skeleton"; }
|
||||
|
||||
// LLViewerVisualParam Virtual functions
|
||||
/*virtual*/ F32 getTotalDistortion() { return 0.1f; }
|
||||
/*virtual*/ const LLVector4a& getAvgDistortion() { return mDefaultVec; }
|
||||
|
||||
@@ -86,6 +86,7 @@ public:
|
||||
/*virtual*/ void setWeight(F32 weight, BOOL upload_bake);
|
||||
/*virtual*/ void setAnimationTarget(F32 target_value, BOOL upload_bake);
|
||||
/*virtual*/ void animate(F32 delta, BOOL upload_bake);
|
||||
/*virtual*/ char const* getTypeString(void) const { return "param_alpha"; }
|
||||
|
||||
// LLViewerVisualParam Virtual functions
|
||||
/*virtual*/ F32 getTotalDistortion() { return 1.f; }
|
||||
@@ -177,7 +178,7 @@ public:
|
||||
/*virtual*/ void setWeight(F32 weight, BOOL upload_bake);
|
||||
/*virtual*/ void setAnimationTarget(F32 target_value, BOOL upload_bake);
|
||||
/*virtual*/ void animate(F32 delta, BOOL upload_bake);
|
||||
|
||||
/*virtual*/ char const* getTypeString(void) const { return "param_color"; }
|
||||
|
||||
// LLViewerVisualParam Virtual functions
|
||||
/*virtual*/ F32 getTotalDistortion() { return 1.f; }
|
||||
|
||||
@@ -143,6 +143,12 @@ BOOL LLViewerVisualParam::setInfo(LLViewerVisualParamInfo *info)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//virtual
|
||||
std::string LLViewerVisualParam::getDumpWearableTypeName(void) const
|
||||
{
|
||||
return LLWearableType::getTypeName(LLWearableType::EType(getInfo()->mWearableType));
|
||||
}
|
||||
|
||||
/*
|
||||
//=============================================================================
|
||||
// These virtual functions should always be overridden,
|
||||
|
||||
@@ -82,6 +82,7 @@ public:
|
||||
|
||||
// LLVisualParam Virtual functions
|
||||
///*virtual*/ BOOL parseData(LLXmlTreeNode* node);
|
||||
/*virtual*/ std::string getDumpWearableTypeName(void) const;
|
||||
|
||||
// New Virtual functions
|
||||
virtual F32 getTotalDistortion() = 0;
|
||||
|
||||
@@ -41,6 +41,7 @@ class LLVisualParam;
|
||||
class LLTexGlobalColorInfo;
|
||||
class LLTexGlobalColor;
|
||||
class LLAvatarAppearance;
|
||||
class AIArchetype;
|
||||
|
||||
// Abstract class.
|
||||
class LLWearable
|
||||
|
||||
@@ -162,6 +162,10 @@ public:
|
||||
void setParamLocation(EParamLocation loc);
|
||||
EParamLocation getParamLocation() const { return mParamLocation; }
|
||||
|
||||
// Singu extensions. Used for dumping the archtype.
|
||||
virtual char const* getTypeString(void) const = 0;
|
||||
virtual std::string getDumpWearableTypeName(void) const = 0;
|
||||
|
||||
protected:
|
||||
F32 mCurWeight; // current weight
|
||||
F32 mLastWeight; // last weight
|
||||
|
||||
@@ -17,6 +17,8 @@ include_directories(
|
||||
)
|
||||
|
||||
set(llcommon_SOURCE_FILES
|
||||
aialert.cpp
|
||||
aifile.cpp
|
||||
aiframetimer.cpp
|
||||
aithreadid.cpp
|
||||
imageids.cpp
|
||||
@@ -106,6 +108,8 @@ set(llcommon_SOURCE_FILES
|
||||
set(llcommon_HEADER_FILES
|
||||
CMakeLists.txt
|
||||
|
||||
aialert.h
|
||||
aifile.h
|
||||
aiframetimer.h
|
||||
airecursive.h
|
||||
aithreadid.h
|
||||
|
||||
75
indra/llcommon/aialert.cpp
Normal file
75
indra/llcommon/aialert.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* @file aialert.cpp
|
||||
*
|
||||
* Copyright (c) 2013, Aleric Inglewood.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution.
|
||||
*
|
||||
* CHANGELOG
|
||||
* and additional copyright holders.
|
||||
*
|
||||
* 02/11/2013
|
||||
* - Initial version, written by Aleric Inglewood @ SL
|
||||
*
|
||||
* 05/11/2013
|
||||
* Moved everything in namespace AIAlert, except AIArgs.
|
||||
*/
|
||||
|
||||
#include "aialert.h"
|
||||
|
||||
namespace AIAlert
|
||||
{
|
||||
|
||||
Error::Error(Prefix const& prefix, modal_nt type,
|
||||
std::string const& xml_desc, AIArgs const& args) : mModal(type)
|
||||
{
|
||||
if (prefix) mLines.push_back(Line(prefix));
|
||||
mLines.push_back(Line(xml_desc, args));
|
||||
}
|
||||
|
||||
Error::Error(Prefix const& prefix, modal_nt type,
|
||||
Error const& alert,
|
||||
std::string const& xml_desc, AIArgs const& args) : mLines(alert.mLines), mModal(type)
|
||||
{
|
||||
if (alert.mModal == modal) mModal = modal;
|
||||
if (prefix) mLines.push_back(Line(prefix, !mLines.empty()));
|
||||
mLines.push_back(Line(xml_desc, args));
|
||||
}
|
||||
|
||||
Error::Error(Prefix const& prefix, modal_nt type,
|
||||
std::string const& xml_desc,
|
||||
Error const& alert) : mLines(alert.mLines), mModal(type)
|
||||
{
|
||||
if (alert.mModal == modal) mModal = modal;
|
||||
if (!mLines.empty()) { mLines.front().set_newline(); }
|
||||
mLines.push_front(Line(xml_desc));
|
||||
if (prefix) mLines.push_front(Line(prefix));
|
||||
}
|
||||
|
||||
Error::Error(Prefix const& prefix, modal_nt type,
|
||||
std::string const& xml_desc, AIArgs const& args,
|
||||
Error const& alert) : mLines(alert.mLines), mModal(type)
|
||||
{
|
||||
if (alert.mModal == modal) mModal = modal;
|
||||
if (!mLines.empty()) { mLines.front().set_newline(); }
|
||||
mLines.push_front(Line(xml_desc, args));
|
||||
if (prefix) mLines.push_front(Line(prefix));
|
||||
}
|
||||
|
||||
} // namespace AIAlert
|
||||
|
||||
293
indra/llcommon/aialert.h
Normal file
293
indra/llcommon/aialert.h
Normal file
@@ -0,0 +1,293 @@
|
||||
/**
|
||||
* @file aialert.h
|
||||
* @brief Declaration of AIArgs and AIAlert classes.
|
||||
*
|
||||
* Copyright (c) 2013, Aleric Inglewood.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution.
|
||||
*
|
||||
* CHANGELOG
|
||||
* and additional copyright holders.
|
||||
*
|
||||
* 02/11/2013
|
||||
* Initial version, written by Aleric Inglewood @ SL
|
||||
*
|
||||
* 05/11/2013
|
||||
* Moved everything in namespace AIAlert, except AIArgs.
|
||||
*/
|
||||
|
||||
#ifndef AI_ALERT
|
||||
#define AI_ALERT
|
||||
|
||||
#include "llpreprocessor.h"
|
||||
#include "llstring.h"
|
||||
#include <deque>
|
||||
#include <exception>
|
||||
|
||||
//===================================================================================================================================
|
||||
// Facility to throw errors that can easily be converted to an informative pop-up floater for the user.
|
||||
|
||||
// Throw arbitrary class.
|
||||
#define THROW_ALERT_CLASS(Alert, ...) throw Alert(AIAlert::Prefix(), AIAlert::not_modal, __VA_ARGS__)
|
||||
#define THROW_MALERT_CLASS(Alert, ...) throw Alert(AIAlert::Prefix(), AIAlert::modal, __VA_ARGS__)
|
||||
#define THROW_FALERT_CLASS(Alert, ...) throw Alert(AIAlert::Prefix(__PRETTY_FUNCTION__, AIAlert::pretty_function_prefix), AIAlert::not_modal, __VA_ARGS__)
|
||||
#define THROW_FMALERT_CLASS(Alert, ...) throw Alert(AIAlert::Prefix(__PRETTY_FUNCTION__, AIAlert::pretty_function_prefix), AIAlert::modal, __VA_ARGS__)
|
||||
|
||||
// Shortcut to throw AIAlert::Error.
|
||||
#define THROW_ALERT(...) THROW_ALERT_CLASS(AIAlert::Error, __VA_ARGS__)
|
||||
#define THROW_MALERT(...) THROW_MALERT_CLASS(AIAlert::Error, __VA_ARGS__)
|
||||
#define THROW_FALERT(...) THROW_FALERT_CLASS(AIAlert::Error, __VA_ARGS__)
|
||||
#define THROW_FMALERT(...) THROW_FMALERT_CLASS(AIAlert::Error, __VA_ARGS__)
|
||||
|
||||
// Shortcut to throw AIAlert::ErrorCode.
|
||||
#define THROW_ALERTC(...) THROW_ALERT_CLASS(AIAlert::ErrorCode, __VA_ARGS__)
|
||||
#define THROW_MALERTC(...) THROW_MALERT_CLASS(AIAlert::ErrorCode, __VA_ARGS__)
|
||||
#define THROW_FALERTC(...) THROW_FALERT_CLASS(AIAlert::ErrorCode, __VA_ARGS__)
|
||||
#define THROW_FMALERTC(...) THROW_FMALERT_CLASS(AIAlert::ErrorCode, __VA_ARGS__)
|
||||
|
||||
// Shortcut to throw AIAlert::ErrorCode with errno as code.
|
||||
#define THROW_ALERTE(...) do { int errn = errno; THROW_ALERT_CLASS(AIAlert::ErrorCode, errn, __VA_ARGS__); } while(0)
|
||||
#define THROW_MALERTE(...) do { int errn = errno; THROW_MALERT_CLASS(AIAlert::ErrorCode, errn, __VA_ARGS__); } while(0)
|
||||
#define THROW_FALERTE(...) do { int errn = errno; THROW_FALERT_CLASS(AIAlert::ErrorCode, errn, __VA_ARGS__); } while(0)
|
||||
#define THROW_FMALERTE(...) do { int errn = errno; THROW_FMALERT_CLASS(AIAlert::ErrorCode, errn, __VA_ARGS__); } while(0)
|
||||
|
||||
// Examples
|
||||
|
||||
#ifdef EXAMPLE_CODE
|
||||
|
||||
//----------------------------------------------------------
|
||||
// To show the alert box:
|
||||
|
||||
catch (AIAlert::Error const& error)
|
||||
{
|
||||
AIAlert::add(error); // Optionally pass pretty_function_prefix as second parameter to *suppress* that output.
|
||||
}
|
||||
|
||||
// or, for example
|
||||
|
||||
catch (AIAlert::ErrorCode const& error)
|
||||
{
|
||||
if (error.getCode() != EEXIST)
|
||||
{
|
||||
AIAlert::add(alert, AIAlert::pretty_function_prefix);
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------
|
||||
// To throw alerts:
|
||||
|
||||
THROW_ALERT("ExampleKey"); // A) Lookup "ExampleKey" in strings.xml and show translation.
|
||||
THROW_ALERT("ExampleKey", AIArgs("[FIRST]", first)("[SECOND]", second)(...etc...)); // B) Same as A, but replace [FIRST] with first, [SECOND] with second, etc.
|
||||
THROW_ALERT("ExampleKey", error); // C) As A, but followed by a colon and a newline, and then the text of 'error'.
|
||||
THROW_ALERT(error, "ExampleKey"); // D) The text of 'error', followed by a colon and a newline and then as A.
|
||||
THROW_ALERT("ExampleKey", AIArgs("[FIRST]", first)("[SECOND]", second), error); // E) As B, but followed by a colon and a newline, and then the text of 'error'.
|
||||
THROW_ALERT(error, "ExampleKey", AIArgs("[FIRST]", first)("[SECOND]", second)); // F) The text of 'error', followed by a colon and a newline and then as B.
|
||||
// where 'error' is a caught Error object (as above) in a rethrow.
|
||||
// Prepend ALERT with M and/or F to make the alert box Modal and/or prepend the text with the current function name.
|
||||
// For example,
|
||||
THROW_MFALERT("ExampleKey", AIArgs("[FIRST]", first)); // Throw a Modal alert box that is prefixed with the current Function name.
|
||||
// Append E after ALERT to throw an ErrorCode class that contains the current errno.
|
||||
// For example,
|
||||
THROW_FALERTE("ExampleKey", AIArgs("[FIRST]", first)); // Throw an alert box that is prefixed with the current Function name and pass errno to the catcher.
|
||||
|
||||
#endif // EXAMPLE_CODE
|
||||
|
||||
//
|
||||
//===================================================================================================================================
|
||||
|
||||
// A wrapper around LLStringUtil::format_map_t to allow constructing a dictionary
|
||||
// on one line by doing:
|
||||
//
|
||||
// AIArgs("[ARG1]", arg1)("[ARG2]", arg2)("[ARG3]", arg3)...
|
||||
|
||||
class LL_COMMON_API AIArgs
|
||||
{
|
||||
private:
|
||||
LLStringUtil::format_map_t mArgs; // The underlying replacement map.
|
||||
|
||||
public:
|
||||
// Construct an empty map.
|
||||
AIArgs(void) { }
|
||||
// Construct a map with a single replacement.
|
||||
AIArgs(char const* key, std::string const& replacement) { mArgs[key] = replacement; }
|
||||
// Add another replacement.
|
||||
AIArgs& operator()(char const* key, std::string const& replacement) { mArgs[key] = replacement; return *this; }
|
||||
// The destructor may not throw.
|
||||
~AIArgs() throw() { }
|
||||
|
||||
// Accessor.
|
||||
LLStringUtil::format_map_t const& operator*() const { return mArgs; }
|
||||
};
|
||||
|
||||
namespace AIAlert
|
||||
{
|
||||
|
||||
enum modal_nt
|
||||
{
|
||||
not_modal,
|
||||
modal
|
||||
};
|
||||
|
||||
enum alert_line_type_nt
|
||||
{
|
||||
normal = 0,
|
||||
empty_prefix = 1,
|
||||
pretty_function_prefix = 2
|
||||
// These must exist of single bits (a mask).
|
||||
};
|
||||
|
||||
// An Prefix currently comes only in two flavors:
|
||||
//
|
||||
// empty_prefix : An empty prefix.
|
||||
// pretty_function_prefix : A function name prefix, this is the function from which the alert was thrown.
|
||||
|
||||
class LL_COMMON_API Prefix
|
||||
{
|
||||
public:
|
||||
Prefix(void) : mType(empty_prefix) { }
|
||||
Prefix(char const* str, alert_line_type_nt type) : mStr(str), mType(type) { }
|
||||
|
||||
operator bool(void) const { return mType != empty_prefix; }
|
||||
alert_line_type_nt type(void) const { return mType; }
|
||||
std::string const& str(void) const { return mStr; }
|
||||
|
||||
private:
|
||||
std::string mStr; // Literal text. For example a C++ function name.
|
||||
alert_line_type_nt mType; // The type of this prefix.
|
||||
};
|
||||
|
||||
// A class that represents one line with its replacements.
|
||||
// The string mXmlDesc shall be looked up in strings.xml.
|
||||
// This is not done as part of this class because LLTrans::getString
|
||||
// is not part of llcommon.
|
||||
|
||||
class LL_COMMON_API Line
|
||||
{
|
||||
private:
|
||||
bool mNewline; // Prepend this line with a newline if set.
|
||||
std::string mXmlDesc; // The keyword to look up in string.xml.
|
||||
AIArgs mArgs; // Replacement map.
|
||||
alert_line_type_nt mType; // The type of this line: normal for normal lines, other for prefixes.
|
||||
|
||||
public:
|
||||
Line(std::string const& xml_desc, bool newline = false) : mNewline(newline), mXmlDesc(xml_desc), mType(normal) { }
|
||||
Line(std::string const& xml_desc, AIArgs const& args, bool newline = false) : mNewline(newline), mXmlDesc(xml_desc), mArgs(args), mType(normal) { }
|
||||
Line(Prefix const& prefix, bool newline = false) : mNewline(newline), mXmlDesc("AIPrefix"), mArgs("[PREFIX]", prefix.str()), mType(prefix.type()) { }
|
||||
// The destructor may not throw.
|
||||
~Line() throw() { }
|
||||
|
||||
// Prepend a newline before this line.
|
||||
void set_newline(void) { mNewline = true; }
|
||||
|
||||
// These are to be used like: LLTrans::getString(line.getXmlDesc(), line.args()) and prepend with a \n if prepend_newline() returns true.
|
||||
std::string getXmlDesc(void) const { return mXmlDesc; }
|
||||
LLStringUtil::format_map_t const& args(void) const { return *mArgs; }
|
||||
bool prepend_newline(void) const { return mNewline; }
|
||||
|
||||
// Accessors.
|
||||
bool suppressed(unsigned int suppress_mask) const { return (suppress_mask & mType) != 0; }
|
||||
bool is_prefix(void) const { return mType != normal; }
|
||||
};
|
||||
|
||||
// This class is used to throw an error that will cause
|
||||
// an alert box to pop up for the user.
|
||||
//
|
||||
// An alert box only has text and an OK button.
|
||||
// The alert box does not give feed back to the program; it is purely informational.
|
||||
|
||||
// The class represents multiple lines, each line is to be translated and catenated,
|
||||
// separated by newlines, and then written to an alert box. This is not done as part
|
||||
// of this class because LLTrans::getString and LLNotification is not part of llcommon.
|
||||
// Instead call LLNotificationUtil::add(Error const&).
|
||||
|
||||
class LL_COMMON_API Error : public std::exception
|
||||
{
|
||||
public:
|
||||
typedef std::deque<Line> lines_type;
|
||||
|
||||
// The destructor may not throw.
|
||||
~Error() throw() { }
|
||||
|
||||
// Accessors.
|
||||
lines_type const& lines(void) const { return mLines; }
|
||||
bool is_modal(void) const { return mModal == modal; }
|
||||
|
||||
// A string with zero or more replacements.
|
||||
Error(Prefix const& prefix, modal_nt type,
|
||||
std::string const& xml_desc, AIArgs const& args = AIArgs());
|
||||
|
||||
// Same as above bit prepending the message with the text of another alert.
|
||||
Error(Prefix const& prefix, modal_nt type,
|
||||
Error const& alert,
|
||||
std::string const& xml_desc, AIArgs const& args = AIArgs());
|
||||
|
||||
// Same as above but appending the message with the text of another alert.
|
||||
// (no args)
|
||||
Error(Prefix const& prefix, modal_nt type,
|
||||
std::string const& xml_desc,
|
||||
Error const& alert);
|
||||
// (with args)
|
||||
Error(Prefix const& prefix, modal_nt type,
|
||||
std::string const& xml_desc, AIArgs const& args,
|
||||
Error const& alert);
|
||||
|
||||
private:
|
||||
lines_type mLines; // The lines (or prefixes) of text to be displayed, each consisting on a keyword (to be looked up in strings.xml) and a replacement map.
|
||||
modal_nt mModal; // If true, make the alert box a modal floater.
|
||||
};
|
||||
|
||||
// Same as Error but allows to pass an additional error code.
|
||||
|
||||
class LL_COMMON_API ErrorCode : public Error
|
||||
{
|
||||
private:
|
||||
int mCode;
|
||||
|
||||
public:
|
||||
// The destructor may not throw.
|
||||
~ErrorCode() throw() { }
|
||||
|
||||
// Accessor.
|
||||
int getCode(void) const { return mCode; }
|
||||
|
||||
// A string with zero or more replacements.
|
||||
ErrorCode(Prefix const& prefix, modal_nt type, int code,
|
||||
std::string const& xml_desc, AIArgs const& args = AIArgs()) :
|
||||
Error(prefix, modal, xml_desc, args) { }
|
||||
|
||||
// Same as above bit prepending the message with the text of another alert.
|
||||
ErrorCode(Prefix const& prefix, modal_nt type, int code,
|
||||
Error const& alert,
|
||||
std::string const& xml_desc, AIArgs const& args = AIArgs()) :
|
||||
Error(prefix, modal, alert, xml_desc, args) { }
|
||||
|
||||
// Same as above but appending the message with the text of another alert.
|
||||
// (no args)
|
||||
ErrorCode(Prefix const& prefix, modal_nt type, int code,
|
||||
std::string const& xml_desc,
|
||||
Error const& alert) :
|
||||
Error(prefix, modal, xml_desc, alert) { }
|
||||
// (with args)
|
||||
ErrorCode(Prefix const& prefix, modal_nt type, int code,
|
||||
std::string const& xml_desc, AIArgs const& args,
|
||||
Error const& alert) :
|
||||
Error(prefix, modal, xml_desc, args, alert) { }
|
||||
};
|
||||
|
||||
} // namespace AIAlert
|
||||
|
||||
#endif // AI_ALERT
|
||||
118
indra/llcommon/aifile.cpp
Normal file
118
indra/llcommon/aifile.cpp
Normal file
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* @file aifile.cpp
|
||||
* @brief POSIX file operations that throw on error.
|
||||
*
|
||||
* Copyright (c) 2013, Aleric Inglewood.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution.
|
||||
*
|
||||
* CHANGELOG
|
||||
* and additional copyright holders.
|
||||
*
|
||||
* 03/11/2013
|
||||
* Initial version, written by Aleric Inglewood @ SL
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "aifile.h"
|
||||
#include "aialert.h"
|
||||
|
||||
#if LL_WINDOWS
|
||||
#include <windows.h>
|
||||
#include <stdlib.h> // Windows errno
|
||||
#else
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
AIFile::AIFile(std::string const& filename, char const* accessmode)
|
||||
{
|
||||
mFp = AIFile::fopen(filename, accessmode);
|
||||
}
|
||||
|
||||
AIFile::~AIFile()
|
||||
{
|
||||
AIFile::close(mFp);
|
||||
}
|
||||
|
||||
// Like THROW_MALERTE but appends "LLFile::strerr(errn) << " (" << errn << ')'" as argument to replace [ERROR].
|
||||
#define THROW_ERROR(...) \
|
||||
do { \
|
||||
int errn = errno; \
|
||||
std::ostringstream error; \
|
||||
error << LLFile::strerr(errn) << " (" << errn << ')'; \
|
||||
THROW_MALERT_CLASS(AIAlert::ErrorCode, errn, __VA_ARGS__ ("[ERROR]", error.str())); \
|
||||
} while(0)
|
||||
|
||||
//static
|
||||
void AIFile::mkdir(std::string const& dirname, int perms)
|
||||
{
|
||||
int rc = LLFile::mkdir(dirname, perms);
|
||||
if (rc < 0 && rc != EEXIST)
|
||||
{
|
||||
THROW_ERROR("AIFile_mkdir_Failed_to_create_DIRNAME", AIArgs("[DIRNAME]", dirname));
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void AIFile::rmdir(std::string const& dirname)
|
||||
{
|
||||
int rc = LLFile::rmdir(dirname);
|
||||
if (rc < 0 && rc != ENOENT)
|
||||
{
|
||||
THROW_ERROR("AIFile_rmdir_Failed_to_remove_DIRNAME", AIArgs("[DIRNAME]", dirname));
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
LLFILE* AIFile::fopen(std::string const& filename, const char* mode)
|
||||
{
|
||||
LLFILE* fp = LLFile::fopen(filename, mode);
|
||||
if (!fp)
|
||||
{
|
||||
THROW_ERROR("AIFile_fopen_Failed_to_open_FILENAME", AIArgs("[FILENAME]", filename));
|
||||
}
|
||||
return fp;
|
||||
}
|
||||
|
||||
//static
|
||||
void AIFile::close(LLFILE* file)
|
||||
{
|
||||
if (LLFile::close(file) < 0)
|
||||
{
|
||||
THROW_ERROR("AIFile_close_Failed_to_close_file", AIArgs);
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void AIFile::remove(std::string const& filename)
|
||||
{
|
||||
if (LLFile::remove(filename) < 0)
|
||||
{
|
||||
THROW_ERROR("AIFile_remove_Failed_to_remove_FILENAME", AIArgs("[FILENAME]", filename));
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void AIFile::rename(std::string const& filename, std::string const& newname)
|
||||
{
|
||||
if (LLFile::rename(filename, newname) < 0)
|
||||
{
|
||||
THROW_ERROR("AIFile_rename_Failed_to_rename_FILE_to_NEWFILE", AIArgs("[FILE]", filename)("[NEWFILE]", newname));
|
||||
}
|
||||
}
|
||||
|
||||
59
indra/llcommon/aifile.h
Normal file
59
indra/llcommon/aifile.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* @file aifile.h
|
||||
* @brief Declaration of AIFile.
|
||||
*
|
||||
* Copyright (c) 2013, Aleric Inglewood.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution.
|
||||
*
|
||||
* CHANGELOG
|
||||
* and additional copyright holders.
|
||||
*
|
||||
* 02/11/2013
|
||||
* Initial version, written by Aleric Inglewood @ SL
|
||||
*/
|
||||
|
||||
#ifndef AIFILE_H
|
||||
#define AIFILE_H
|
||||
|
||||
#include "llfile.h"
|
||||
|
||||
// As LLFile, but throws AIAlert instead of printing a warning.
|
||||
class LL_COMMON_API AIFile
|
||||
{
|
||||
private:
|
||||
LLFILE* mFp;
|
||||
|
||||
public:
|
||||
// Scoped file (exception safe). Throws AIAlertCode with errno on failure.
|
||||
AIFile(std::string const& filename, char const* accessmode);
|
||||
~AIFile();
|
||||
|
||||
operator LLFILE* () const { return mFp; }
|
||||
|
||||
// All these functions take UTF8 path/filenames.
|
||||
static LLFILE* fopen(std::string const& filename, char const* accessmode);
|
||||
static void close(LLFILE* file);
|
||||
|
||||
static void mkdir(std::string const& dirname, int perms = 0700); // Does NOT throw when dirname already exists.
|
||||
static void rmdir(std::string const& dirname); // Does NOT throw when dirname does not exist.
|
||||
static void remove(std::string const& filename); // Does NOT throw when filename does not exist.
|
||||
static void rename(std::string const& filename, std::string const& newname);
|
||||
};
|
||||
|
||||
#endif // AIFILE_H
|
||||
@@ -49,7 +49,8 @@ static std::string empty;
|
||||
|
||||
#if LL_WINDOWS
|
||||
// On Windows, use strerror_s().
|
||||
std::string strerr(int errn)
|
||||
//static
|
||||
std::string LLFile::strerr(int errn)
|
||||
{
|
||||
char buffer[256];
|
||||
strerror_s(buffer, errn); // infers sizeof(buffer) -- love it!
|
||||
@@ -98,7 +99,8 @@ std::string message_from(int orig_errno, const char* buffer, size_t bufflen,
|
||||
<< " (error " << stre_errno << ')');
|
||||
}
|
||||
|
||||
std::string strerr(int errn)
|
||||
//static
|
||||
std::string LLFile::strerr(int errn)
|
||||
{
|
||||
char buffer[256];
|
||||
// Select message_from() function matching the strerror_r() we have on hand.
|
||||
@@ -108,7 +110,8 @@ std::string strerr(int errn)
|
||||
#endif // ! LL_WINDOWS
|
||||
|
||||
// On either system, shorthand call just infers global 'errno'.
|
||||
std::string strerr()
|
||||
//static
|
||||
std::string LLFile::strerr()
|
||||
{
|
||||
return strerr(errno);
|
||||
}
|
||||
@@ -125,7 +128,7 @@ int warnif(const std::string& desc, const std::string& filename, int rc, int acc
|
||||
if (errn != accept)
|
||||
{
|
||||
LL_WARNS("LLFile") << "Couldn't " << desc << " '" << filename
|
||||
<< "' (errno " << errn << "): " << strerr(errn) << LL_ENDL;
|
||||
<< "' (errno " << errn << "): " << LLFile::strerr(errn) << LL_ENDL;
|
||||
}
|
||||
#if 0 && LL_WINDOWS // turn on to debug file-locking problems
|
||||
// If the problem is "Permission denied," maybe it's because another
|
||||
|
||||
@@ -30,6 +30,9 @@
|
||||
#ifndef LL_LLFILE_H
|
||||
#define LL_LLFILE_H
|
||||
|
||||
#include <fstream>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/**
|
||||
* This class provides a cross platform interface to the filesystem.
|
||||
* Attempts to mostly mirror the POSIX style IO functions.
|
||||
@@ -37,9 +40,6 @@
|
||||
|
||||
typedef FILE LLFILE;
|
||||
|
||||
#include <fstream>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if LL_WINDOWS
|
||||
// windows version of stat function and stat data structure are called _stat
|
||||
typedef struct _stat llstat;
|
||||
@@ -82,6 +82,9 @@ public:
|
||||
std::ios::openmode mode);
|
||||
|
||||
static const char * tmpdir();
|
||||
|
||||
static std::string strerr(int errn);
|
||||
static std::string strerr();
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -281,7 +281,12 @@ void LLMD5::raw_digest(unsigned char *s) const
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//Singu extension: the inverse of LLMD5::raw_digest.
|
||||
void LLMD5::clone(unsigned char const* s)
|
||||
{
|
||||
memcpy(digest, s, 16);
|
||||
finalized = 1;
|
||||
}
|
||||
|
||||
void LLMD5::hex_digest(char *s) const
|
||||
{
|
||||
@@ -305,12 +310,26 @@ void LLMD5::hex_digest(char *s) const
|
||||
return;
|
||||
}
|
||||
|
||||
//Singu extension: the inverse of LLMD5::hex_digest.
|
||||
void LLMD5::clone(std::string const& hash_str)
|
||||
{
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
unsigned char byte = 0;
|
||||
for (int j = 0; j < 2; ++j)
|
||||
{
|
||||
char c = hash_str[i * 2 + j];
|
||||
unsigned char nibble = (c >= '0' && c <= '9') ? c - '0' : c - 'a' + 10;
|
||||
byte += nibble << ((1 - j) << 2);
|
||||
}
|
||||
digest[i] = byte;
|
||||
}
|
||||
finalized = 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
std::ostream& operator<<(std::ostream &stream, LLMD5 context)
|
||||
std::ostream& operator<<(std::ostream &stream, LLMD5 const& context)
|
||||
{
|
||||
char s[33]; /* Flawfinder: ignore */
|
||||
context.hex_digest(s);
|
||||
@@ -318,23 +337,6 @@ std::ostream& operator<<(std::ostream &stream, LLMD5 context)
|
||||
return stream;
|
||||
}
|
||||
|
||||
bool operator==(const LLMD5& a, const LLMD5& b)
|
||||
{
|
||||
unsigned char a_guts[16];
|
||||
unsigned char b_guts[16];
|
||||
a.raw_digest(a_guts);
|
||||
b.raw_digest(b_guts);
|
||||
if (memcmp(a_guts,b_guts,16)==0)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator!=(const LLMD5& a, const LLMD5& b)
|
||||
{
|
||||
return !(a==b);
|
||||
}
|
||||
|
||||
// PRIVATE METHODS:
|
||||
|
||||
void LLMD5::init(){
|
||||
|
||||
@@ -32,6 +32,10 @@
|
||||
#ifndef LL_LLMD5_H
|
||||
#define LL_LLMD5_H
|
||||
|
||||
#include "llpreprocessor.h"
|
||||
#include <iosfwd>
|
||||
#include <cstring> // memcmp
|
||||
|
||||
// LLMD5.CC - source code for the C++/object oriented translation and
|
||||
// modification of MD5.
|
||||
|
||||
@@ -98,18 +102,27 @@ public:
|
||||
void update (const std::string& str);
|
||||
void finalize ();
|
||||
|
||||
bool isFinalized() const { return finalized; }
|
||||
|
||||
// constructors for special circumstances. All these constructors finalize
|
||||
// the MD5 context.
|
||||
LLMD5 (const unsigned char *string); // digest string, finalize
|
||||
LLMD5 (std::istream& stream); // digest stream, finalize
|
||||
LLMD5 (FILE *file); // digest file, close, finalize
|
||||
LLMD5 (const unsigned char *string, const unsigned int number);
|
||||
|
||||
// Singu extension: set digest directly, finalize.
|
||||
void clone(unsigned char const* digest); // Inverse of raw_digest.
|
||||
void clone(std::string const& hash_str); // Inverse of hex_digest.
|
||||
|
||||
// methods to acquire finalized result
|
||||
void raw_digest(unsigned char *array) const; // provide 16-byte array for binary data
|
||||
void hex_digest(char *string) const; // provide 33-byte array for ascii-hex string
|
||||
|
||||
friend LL_COMMON_API std::ostream& operator<< (std::ostream&, LLMD5 context);
|
||||
friend LL_COMMON_API std::ostream& operator<< (std::ostream&, LLMD5 const& context);
|
||||
friend LL_COMMON_API bool operator==(const LLMD5& a, const LLMD5& b) { return std::memcmp(a.digest ,b.digest, 16) == 0; }
|
||||
friend LL_COMMON_API bool operator!=(const LLMD5& a, const LLMD5& b) { return std::memcmp(a.digest ,b.digest, 16) != 0; }
|
||||
friend LL_COMMON_API bool operator<(const LLMD5& a, const LLMD5& b) { return std::memcmp(a.digest ,b.digest, 16) < 0; }
|
||||
|
||||
private:
|
||||
|
||||
@@ -131,7 +144,4 @@ private:
|
||||
|
||||
};
|
||||
|
||||
LL_COMMON_API bool operator==(const LLMD5& a, const LLMD5& b);
|
||||
LL_COMMON_API bool operator!=(const LLMD5& a, const LLMD5& b);
|
||||
|
||||
#endif // LL_LLMD5_H
|
||||
|
||||
@@ -27,6 +27,9 @@
|
||||
#define LLREFCOUNT_H
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include "llpreprocessor.h" // LL_COMMON_API
|
||||
#include "stdtypes.h" // S32
|
||||
#include "llerror.h" // llassert
|
||||
|
||||
#define LL_REF_COUNT_DEBUG 0
|
||||
#if LL_REF_COUNT_DEBUG
|
||||
|
||||
@@ -37,6 +37,8 @@
|
||||
|
||||
#include <vector>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include "llpreprocessor.h"
|
||||
#include "stdtypes.h"
|
||||
|
||||
class LLRunnable;
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "llerror.h" // *TODO: eliminate this
|
||||
|
||||
#include <map>
|
||||
#include <typeinfo>
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
|
||||
@@ -231,7 +231,9 @@ public:
|
||||
operator std::string() const { return mString; }
|
||||
bool operator<(const LLFormatMapString& rhs) const { return mString < rhs.mString; }
|
||||
std::size_t length() const { return mString.length(); }
|
||||
|
||||
// The destructor may not throw.
|
||||
~LLFormatMapString() throw() { }
|
||||
|
||||
private:
|
||||
std::string mString;
|
||||
};
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include "stdtypes.h"
|
||||
#include "llpreprocessor.h"
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "lltrans.h"
|
||||
|
||||
#include "llnotifications.h"
|
||||
#include "aialert.h"
|
||||
|
||||
#include "../newview/hippogridmanager.h"
|
||||
|
||||
@@ -1479,6 +1480,32 @@ LLNotificationPtr LLNotifications::add(const LLNotification::Params& p)
|
||||
return pNotif;
|
||||
}
|
||||
|
||||
LLNotificationPtr LLNotifications::add(AIAlert::Error const& error, int type, unsigned int suppress_mask)
|
||||
{
|
||||
std::string alert_text;
|
||||
bool suppress_newlines = false;
|
||||
bool last_was_prefix = false;
|
||||
for (AIAlert::Error::lines_type::const_iterator line = error.lines().begin(); line != error.lines().end(); ++line)
|
||||
{
|
||||
// Even if a line is suppressed, we print its leading newline if requested, but never more than one.
|
||||
if (!suppress_newlines && line->prepend_newline())
|
||||
{
|
||||
alert_text += '\n';
|
||||
suppress_newlines = true;
|
||||
}
|
||||
if (!line->suppressed(suppress_mask))
|
||||
{
|
||||
if (last_was_prefix) alert_text += ' '; // The translation system strips off spaces... add them back.
|
||||
alert_text += LLTrans::getString(line->getXmlDesc(), line->args());
|
||||
suppress_newlines = false;
|
||||
last_was_prefix = line->is_prefix();
|
||||
}
|
||||
}
|
||||
LLSD substitutions = LLSD::emptyMap();
|
||||
substitutions["[PAYLOAD]"] = alert_text;
|
||||
return add(LLNotification::Params((type == AIAlert::modal || error.is_modal()) ? "AIAlertModal" : "AIAlert").substitutions(substitutions));
|
||||
}
|
||||
|
||||
|
||||
void LLNotifications::add(const LLNotificationPtr pNotif)
|
||||
{
|
||||
|
||||
@@ -108,6 +108,8 @@
|
||||
#include "llnotificationptr.h"
|
||||
#include "llnotificationcontext.h"
|
||||
|
||||
namespace AIAlert { class Error; }
|
||||
|
||||
typedef enum e_notification_priority
|
||||
{
|
||||
NOTIFICATION_PRIORITY_UNSPECIFIED,
|
||||
@@ -737,6 +739,7 @@ public:
|
||||
const LLSD& substitutions,
|
||||
const LLSD& payload,
|
||||
LLNotificationFunctorRegistry::ResponseFunctor functor);
|
||||
LLNotificationPtr add(AIAlert::Error const& error, int type, unsigned int suppress_mask);
|
||||
LLNotificationPtr add(const LLNotification::Params& p);
|
||||
|
||||
void forceResponse(const LLNotification::Params& params, S32 option);
|
||||
|
||||
@@ -30,6 +30,46 @@
|
||||
#include "llsd.h"
|
||||
#include "llxmlnode.h" // apparently needed to call LLNotifications::instance()
|
||||
|
||||
namespace AIAlert
|
||||
{
|
||||
|
||||
LLNotificationPtr add(Error const& error, modal_nt type, unsigned int suppress_mask)
|
||||
{
|
||||
return LLNotifications::instance().add(error, type, suppress_mask);
|
||||
}
|
||||
|
||||
LLNotificationPtr add(std::string const& xml_desc, modal_nt type)
|
||||
{
|
||||
return LLNotifications::instance().add(Error(Prefix(), type, xml_desc, AIArgs()), type, 0);
|
||||
}
|
||||
|
||||
LLNotificationPtr add(std::string const& xml_desc, AIArgs const& args, modal_nt type)
|
||||
{
|
||||
return LLNotifications::instance().add(Error(Prefix(), type, xml_desc, args), type, 0);
|
||||
}
|
||||
|
||||
LLNotificationPtr add(Error const& error, std::string const& xml_desc, unsigned int suppress_mask, modal_nt type)
|
||||
{
|
||||
return LLNotifications::instance().add(Error(Prefix(), type, error, xml_desc, AIArgs()), type, suppress_mask);
|
||||
}
|
||||
|
||||
LLNotificationPtr add(Error const& error, std::string const& xml_desc, AIArgs const& args, unsigned int suppress_mask, modal_nt type)
|
||||
{
|
||||
return LLNotifications::instance().add(Error(Prefix(), type, error, xml_desc, args), type, suppress_mask);
|
||||
}
|
||||
|
||||
LLNotificationPtr add(std::string const& xml_desc, Error const& error, unsigned int suppress_mask, modal_nt type)
|
||||
{
|
||||
return LLNotifications::instance().add(Error(Prefix(), type, xml_desc, AIArgs(), error), type, suppress_mask);
|
||||
}
|
||||
|
||||
LLNotificationPtr add(std::string const& xml_desc, AIArgs const& args, Error const& error, unsigned int suppress_mask, modal_nt type)
|
||||
{
|
||||
return LLNotifications::instance().add(Error(Prefix(), type, xml_desc, args, error), type, suppress_mask);
|
||||
}
|
||||
|
||||
} // namespace AIAlert
|
||||
|
||||
LLNotificationPtr LLNotificationsUtil::add(const std::string& name)
|
||||
{
|
||||
return LLNotifications::instance().add(
|
||||
|
||||
@@ -30,11 +30,51 @@
|
||||
// to avoid including the heavyweight llnotifications.h
|
||||
|
||||
#include "llnotificationptr.h"
|
||||
#include "aialert.h"
|
||||
|
||||
#include <boost/function.hpp>
|
||||
|
||||
class LLSD;
|
||||
|
||||
namespace AIAlert
|
||||
{
|
||||
// Add an alert directly to LLNotifications.
|
||||
|
||||
// Look up xml_desc in strings.xml.
|
||||
LLNotificationPtr add(std::string const& xml_desc,
|
||||
modal_nt type = not_modal);
|
||||
// ... with replacement args.
|
||||
LLNotificationPtr add(std::string const& xml_desc, AIArgs const& args,
|
||||
modal_nt type = not_modal);
|
||||
|
||||
// Append it to an existing alert error.
|
||||
LLNotificationPtr add(Error const& error,
|
||||
std::string const& xml_desc,
|
||||
unsigned int suppress_mask = 0, modal_nt type = not_modal);
|
||||
LLNotificationPtr add(Error const& error,
|
||||
std::string const& xml_desc, AIArgs const& args,
|
||||
unsigned int suppress_mask = 0, modal_nt type = not_modal);
|
||||
// Prepend it to an existing alert error.
|
||||
LLNotificationPtr add(std::string const& xml_desc,
|
||||
Error const& error,
|
||||
unsigned int suppress_mask = 0, modal_nt type = not_modal);
|
||||
LLNotificationPtr add(std::string const& xml_desc, AIArgs const& args,
|
||||
Error const& error,
|
||||
unsigned int suppress_mask = 0, modal_nt type = not_modal);
|
||||
|
||||
// Just show the caught alert error.
|
||||
LLNotificationPtr add(Error const& error,
|
||||
modal_nt type = not_modal, unsigned int suppress_mask = 0);
|
||||
|
||||
// Short cuts for enforcing modal alerts.
|
||||
inline LLNotificationPtr add_modal(std::string const& xml_desc) { return add(xml_desc, modal); }
|
||||
inline LLNotificationPtr add_modal(std::string const& xml_desc, AIArgs const& args) { return add(xml_desc, args, modal); }
|
||||
inline LLNotificationPtr add_modal(Error const& error, std::string const& xml_desc, unsigned int suppress_mask = 0) { return add(error, xml_desc, suppress_mask, modal); }
|
||||
inline LLNotificationPtr add_modal(Error const& error, std::string const& xml_desc, AIArgs const& args, unsigned int suppress_mask = 0) { return add(error, xml_desc, args, suppress_mask, modal); }
|
||||
inline LLNotificationPtr add_modal(std::string const& xml_desc, Error const& error, unsigned int suppress_mask = 0) { return add(xml_desc, error, suppress_mask, modal); }
|
||||
inline LLNotificationPtr add_modal(std::string const& xml_desc, AIArgs const& args, Error const& error, unsigned int suppress_mask = 0) { return add(xml_desc, args, error, suppress_mask, modal); }
|
||||
}
|
||||
|
||||
namespace LLNotificationsUtil
|
||||
{
|
||||
LLNotificationPtr add(const std::string& name);
|
||||
|
||||
@@ -13,6 +13,7 @@ include_directories(
|
||||
)
|
||||
|
||||
set(llxml_SOURCE_FILES
|
||||
aixml.cpp
|
||||
llcontrol.cpp
|
||||
llxmlnode.cpp
|
||||
llxmlparser.cpp
|
||||
@@ -22,6 +23,7 @@ set(llxml_SOURCE_FILES
|
||||
set(llxml_HEADER_FILES
|
||||
CMakeLists.txt
|
||||
|
||||
aixml.h
|
||||
llcontrol.h
|
||||
llcontrolgroupreader.h
|
||||
llxmlnode.h
|
||||
|
||||
609
indra/llxml/aixml.cpp
Normal file
609
indra/llxml/aixml.cpp
Normal file
@@ -0,0 +1,609 @@
|
||||
/**
|
||||
* @file aixml.cpp
|
||||
* @brief XML serialization support.
|
||||
*
|
||||
* Copyright (c) 2013, Aleric Inglewood.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution.
|
||||
*
|
||||
* CHANGELOG
|
||||
* and additional copyright holders.
|
||||
*
|
||||
* 30/07/2013
|
||||
* Initial version, written by Aleric Inglewood @ SL
|
||||
*/
|
||||
|
||||
#include "sys.h"
|
||||
#include "aixml.h"
|
||||
#include "llmd5.h"
|
||||
#include <boost/tokenizer.hpp>
|
||||
#include "aifile.h"
|
||||
|
||||
//=============================================================================
|
||||
// Overview
|
||||
|
||||
// The AIXML* classes provide an Object Oriented way to serialize objects
|
||||
// to and from an XML file.
|
||||
//
|
||||
// The following classes are provided:
|
||||
//
|
||||
// AIXMLRootElement - Write an object to a file (including XML declaration at the top).
|
||||
// AIXMLElement - Write an ojbect to an ostream (just one XML element).
|
||||
//
|
||||
// AIXMLParser - Read and deserialize an XML file written with AIXMLRootElement.
|
||||
// AIXMLElementParser - Read and deserialize an XML stream written with AIXMLElement.
|
||||
//
|
||||
// Classes that need to be written to and from XML would typically
|
||||
// supply two member functions. For example,
|
||||
|
||||
#ifdef EXAMPLE_CODE // undefined
|
||||
|
||||
class HelloWorld {
|
||||
public:
|
||||
// Write object to XML.
|
||||
void toXML(std::ostream& os, int indentation) const;
|
||||
// Read object from XML.
|
||||
HelloWorld(AIXMLElementParser const& parser);
|
||||
|
||||
private:
|
||||
// Example member variables...
|
||||
Attribute1 mAttribute1;
|
||||
Attribute2 mAttribute2;
|
||||
// etc.
|
||||
Custom1 mCustom;
|
||||
std::vector<Custom2> mContainer;
|
||||
LLDate mDate;
|
||||
LLMD5 mMd5;
|
||||
LLUUID mUUID;
|
||||
};
|
||||
|
||||
// Typical serialization member function.
|
||||
void HelloWorld::toXML(std::ostream& os, int indentation) const
|
||||
{
|
||||
AIXMLElement tag(os, "helloworld", indentation);
|
||||
|
||||
// Zero or more attributes:
|
||||
tag.attribute("attributename1", mAttribute1); // Uses operator<<(std::ostream&, Attribute1 const&) to write mAttribute1.
|
||||
tag.attribute("attributename2", mAttribute2); // Uses operator<<(std::ostream&, Attribute2 const&) to write mAttribute2.
|
||||
// etc.
|
||||
|
||||
// Zero or more child elements:
|
||||
tag.child("tagname", mChild1);
|
||||
tag.child(mCustom); // Calls mCustom.toXML() to insert the object.
|
||||
tag.child(mContainer.begin(), mContainer.end()); // Calls tag.child(element) for each element of the container.
|
||||
// Special allowed cases:
|
||||
tag.child(mDate); // Uses "date" as tag name.
|
||||
tag.child(mMd5); // Uses "md5" as tag name.
|
||||
tag.child(mUUID); // Uses "uuid" as tag name.
|
||||
}
|
||||
|
||||
// Typical deserialization member function.
|
||||
HelloWorld::HelloWorld(AIXMLElementParser const& parser)
|
||||
{
|
||||
// Zero or more attributes:
|
||||
parser.attribute("attributename1", "foobar"); // Throws std::runtime_error is attributename1 is missing or does not have the value "foobar".
|
||||
if (!parser.attribute("attributename2", mAttribute2)) // Reads value of attributename2 into mAttribute2 (throws if it could not be parsed).
|
||||
{
|
||||
throw std::runtime_error("..."); // Attribute was missing.
|
||||
}
|
||||
|
||||
// Zero or more child elements:
|
||||
parser.child("tagname", mChild1);
|
||||
parser.child("custom1", mCustom);
|
||||
parser.insert_children("custom2", mContainer);
|
||||
// Special allowed cases:
|
||||
parser.child(mDate);
|
||||
parser.child(mMd5);
|
||||
parser.child(mUUID);
|
||||
}
|
||||
|
||||
// To actually write to an XML file one would do, for example:
|
||||
|
||||
LLFILE* fp = fopen(...);
|
||||
AIXMLRootElement tag(fp, "rootname");
|
||||
tag.attribute("version", "1.0");
|
||||
tag.child(LLDate::now());
|
||||
tag.child(mHelloWorld);
|
||||
|
||||
// And to read it again,
|
||||
|
||||
AIXMLParser helloworld(filename, "description of file used for error reporting", "rootname", 1);
|
||||
helloworld.attribute("version", "1.0");
|
||||
helloworld.child("helloworld", mHelloWorld);
|
||||
|
||||
// Of course, both would need to be in a try { } catch block.
|
||||
|
||||
#endif // EXAMPLE_CODE
|
||||
|
||||
// Do NOT change these - it would break old databases.
|
||||
char const* const DEFAULT_LLUUID_NAME = "uuid";
|
||||
char const* const DEFAULT_MD5STR_NAME = "md5";
|
||||
char const* const DEFAULT_LLDATE_NAME = "date";
|
||||
|
||||
std::string const DEFAULT_MD5STR_ATTRIBUTE_NAME = DEFAULT_MD5STR_NAME;
|
||||
std::string const DEFAULT_LLUUID_ATTRIBUTE_NAME = DEFAULT_LLUUID_NAME;
|
||||
std::string const DEFAULT_LLDATE_ATTRIBUTE_NAME = DEFAULT_LLDATE_NAME;
|
||||
std::string const DEFAULT_VERSION_ATTRIBUTE_NAME = "version";
|
||||
|
||||
struct xdigit {
|
||||
bool isxdigit;
|
||||
xdigit(void) : isxdigit(true) { }
|
||||
void operator()(char c) { isxdigit = isxdigit && std::isxdigit(c); }
|
||||
operator bool() const { return isxdigit; }
|
||||
};
|
||||
|
||||
static bool is_valid_md5str(std::string const& str)
|
||||
{
|
||||
return str.length() == MD5HEX_STR_BYTES && std::for_each(str.begin(), str.end(), xdigit());
|
||||
}
|
||||
|
||||
// Conversion routine that is a lot more strict then LLStringUtil::convertToU32.
|
||||
// This version does not allow leading or trailing spaces, nor does it allow a leading minus sign.
|
||||
// Leading zeroes are not allowed except a 0 by itself.
|
||||
bool convertToU32strict(std::string const& str, U32& value)
|
||||
{
|
||||
bool first = true;
|
||||
value = 0;
|
||||
for (std::string::const_iterator i = str.begin(); i != str.end(); ++i)
|
||||
{
|
||||
if (value == 0 && !first || !std::isdigit(*i)) // Reject leading zeroes and non-digits.
|
||||
return false;
|
||||
value = value * 10 + *i - '0';
|
||||
first = false;
|
||||
}
|
||||
return !first; // Reject empty string.
|
||||
}
|
||||
|
||||
typedef boost::tokenizer<boost::char_separator<char> > boost_tokenizer;
|
||||
|
||||
bool decode_version(std::string const& version, U32& major, U32& minor)
|
||||
{
|
||||
boost_tokenizer tokens(version, boost::char_separator<char>("", "."));
|
||||
boost_tokenizer::const_iterator itTok = tokens.begin();
|
||||
return itTok != tokens.end() && convertToU32strict(*itTok++, major) &&
|
||||
itTok != tokens.end() && *itTok++ == "." &&
|
||||
itTok != tokens.end() && convertToU32strict(*itTok, minor);
|
||||
}
|
||||
|
||||
bool md5strFromXML(LLXmlTreeNode* node, std::string& md5str_out)
|
||||
{
|
||||
static LLStdStringHandle const DEFAULT_MD5STR_ATTRIBUTE_NAME_HANDLE = LLXmlTree::addAttributeString(DEFAULT_MD5STR_ATTRIBUTE_NAME);
|
||||
return node->getFastAttributeString(DEFAULT_MD5STR_ATTRIBUTE_NAME_HANDLE, md5str_out) && is_valid_md5str(md5str_out);
|
||||
}
|
||||
|
||||
bool md5strFromXML(LLXmlTreeNode* node, std::string& md5str_out, std::string const& attribute_name)
|
||||
{
|
||||
return node->getAttributeString(attribute_name, md5str_out) && is_valid_md5str(md5str_out);
|
||||
}
|
||||
|
||||
bool UUIDFromXML(LLXmlTreeNode* node, LLUUID& uuid_out)
|
||||
{
|
||||
static LLStdStringHandle const DEFAULT_LLUUID_ATTRIBUTE_NAME_HANDLE = LLXmlTree::addAttributeString(DEFAULT_LLUUID_ATTRIBUTE_NAME);
|
||||
return node->getFastAttributeUUID(DEFAULT_LLUUID_ATTRIBUTE_NAME_HANDLE, uuid_out);
|
||||
}
|
||||
|
||||
bool UUIDFromXML(LLXmlTreeNode* node, LLUUID& uuid_out, std::string const& attribute_name)
|
||||
{
|
||||
return node->getAttributeUUID(attribute_name, uuid_out);
|
||||
}
|
||||
|
||||
bool dateFromXML(LLXmlTreeNode* node, LLDate& date_out)
|
||||
{
|
||||
static LLStdStringHandle const DEFAULT_LLDATE_ATTRIBUTE_NAME_HANDLE = LLXmlTree::addAttributeString(DEFAULT_LLDATE_ATTRIBUTE_NAME);
|
||||
std::string date_s;
|
||||
return node->getFastAttributeString(DEFAULT_LLDATE_ATTRIBUTE_NAME_HANDLE, date_s) && date_out.fromString(date_s);
|
||||
}
|
||||
|
||||
bool dateFromXML(LLXmlTreeNode* node, LLDate& date_out, std::string const& attribute_name)
|
||||
{
|
||||
std::string date_s;
|
||||
return node->getAttributeString(attribute_name, date_s) && date_out.fromString(date_s);
|
||||
}
|
||||
|
||||
bool versionFromXML(LLXmlTreeNode* node, U32& major_out, U32& minor_out)
|
||||
{
|
||||
static LLStdStringHandle const DEFAULT_VERSION_ATTRIBUTE_NAME_HANDLE = LLXmlTree::addAttributeString(DEFAULT_VERSION_ATTRIBUTE_NAME);
|
||||
major_out = minor_out = 0;
|
||||
std::string version_s;
|
||||
return node->getFastAttributeString(DEFAULT_VERSION_ATTRIBUTE_NAME_HANDLE, version_s) && decode_version(version_s, major_out, minor_out);
|
||||
}
|
||||
|
||||
bool versionFromXML(LLXmlTreeNode* node, U32& major_out, U32& minor_out, std::string const& attribute_name)
|
||||
{
|
||||
major_out = minor_out = 0;
|
||||
std::string version_s;
|
||||
return node->getAttributeString(attribute_name, version_s) && decode_version(version_s, major_out, minor_out);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// AIXMLElement
|
||||
|
||||
AIXMLElement::AIXMLElement(std::ostream& os, char const* name, int indentation) :
|
||||
mOs(os), mName(name), mIndentation(indentation), mHasChildren(false)
|
||||
{
|
||||
mOs << std::string(mIndentation, ' ') << '<' << mName;
|
||||
if (!mOs.good())
|
||||
{
|
||||
THROW_ALERT("AIXMLElement_Failed_to_write_DATA", AIArgs("[DATA]", "<" + mName));
|
||||
}
|
||||
}
|
||||
|
||||
int AIXMLElement::open_child(void)
|
||||
{
|
||||
if (!mHasChildren)
|
||||
{
|
||||
mOs << ">\n";
|
||||
if (!mOs.good())
|
||||
{
|
||||
THROW_ALERT("AIXMLElement_closing_child_Failed_to_write_DATA", AIArgs("[DATA]", ">\\n"));
|
||||
}
|
||||
mHasChildren = true;
|
||||
}
|
||||
mIndentation += 2;
|
||||
return mIndentation;
|
||||
}
|
||||
|
||||
void AIXMLElement::close_child(void)
|
||||
{
|
||||
mIndentation -= 2;
|
||||
}
|
||||
|
||||
AIXMLElement::~AIXMLElement()
|
||||
{
|
||||
if (mHasChildren)
|
||||
{
|
||||
mOs << std::string(mIndentation, ' ') << "</" << mName << ">\n";
|
||||
if (!mOs.good())
|
||||
{
|
||||
THROW_ALERT("AIXMLElement_closing_child_Failed_to_write_DATA",
|
||||
AIArgs("[DATA]", "\\n" + std::string(mIndentation, ' ') + "</" + mName + ">\\n"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mOs << " />\n";
|
||||
if (!mOs.good())
|
||||
{
|
||||
THROW_ALERT("AIXMLElement_closing_child_Failed_to_write_DATA", AIArgs("[DATA]", " />\\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void AIXMLElement::child(LLUUID const& element)
|
||||
{
|
||||
open_child();
|
||||
write_child(DEFAULT_LLUUID_NAME, element);
|
||||
close_child();
|
||||
}
|
||||
|
||||
template<>
|
||||
void AIXMLElement::child(LLMD5 const& element)
|
||||
{
|
||||
open_child();
|
||||
write_child(DEFAULT_MD5STR_NAME, element);
|
||||
close_child();
|
||||
}
|
||||
|
||||
template<>
|
||||
void AIXMLElement::child(LLDate const& element)
|
||||
{
|
||||
open_child();
|
||||
write_child(DEFAULT_LLDATE_NAME, element);
|
||||
close_child();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// AIXMLStream
|
||||
|
||||
AIXMLStream::AIXMLStream(LLFILE* fp, bool standalone) : mOfs(fp)
|
||||
{
|
||||
char const* sp = standalone ? " standalone=\"yes\"" : "";
|
||||
int rc = fprintf(fp, "<?xml version=\"1.0\" encoding=\"utf-8\"%s ?>\n", sp);
|
||||
if (rc < 0 || ferror(fp))
|
||||
{
|
||||
// I don't think that errno is set to anything else but EBADF here,
|
||||
// so there is not really any informative message to add here.
|
||||
THROW_MALERT("AIXMLStream_fprintf_failed_to_write_xml_header");
|
||||
}
|
||||
}
|
||||
|
||||
AIXMLStream::~AIXMLStream()
|
||||
{
|
||||
if (mOfs.is_open())
|
||||
{
|
||||
mOfs.close();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// AIXMLParser
|
||||
|
||||
AIXMLParser::AIXMLParser(std::string const& filename, char const* file_desc, std::string const& name, U32 major_version) :
|
||||
AIXMLElementParser(mFilename, mFileDesc, major_version),
|
||||
mFilename(filename), mFileDesc(file_desc)
|
||||
{
|
||||
char const* error = NULL;
|
||||
AIArgs args;
|
||||
if (!mXmlTree.parseFile(filename, TRUE))
|
||||
{
|
||||
AIFile dummy(filename, "rb"); // Check if the file can be opened at all (throws with a more descriptive error if not).
|
||||
error = "AIXMLParser_Cannot_parse_FILEDESC_FILENAME";
|
||||
}
|
||||
else
|
||||
{
|
||||
mNode = mXmlTree.getRoot();
|
||||
if (!mNode)
|
||||
{
|
||||
error = "AIXMLParser_No_root_node_found_in_FILEDESC_FILENAME";
|
||||
}
|
||||
else if (!mNode->hasName(name))
|
||||
{
|
||||
error = "AIXMLParser_Missing_header_NAME_invalid_FILEDESC_FILENAME";
|
||||
args("[NAME]", name);
|
||||
}
|
||||
else if (!versionFromXML(mNode, mVersionMajor, mVersionMinor))
|
||||
{
|
||||
error = "AIXMLParser_Invalid_or_missing_NAME_version_attribute_in_FILEDESC_FILENAME";
|
||||
args("[NAME]", name);
|
||||
}
|
||||
else if (mVersionMajor != major_version)
|
||||
{
|
||||
error = "AIXMLParser_Incompatible_NAME_version_MAJOR_MINOR_in";
|
||||
args("[NAME]", name)("[MAJOR]", llformat("%u", mVersionMajor))("[MINOR]", llformat("%u", mVersionMinor));
|
||||
}
|
||||
}
|
||||
if (error)
|
||||
{
|
||||
THROW_MALERT(error, args("[FILEDESC]", mFileDesc)("[FILENAME]", mFilename));
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// AIXMLElementParser
|
||||
|
||||
template<>
|
||||
LLMD5 AIXMLElementParser::read_string(std::string const& value) const
|
||||
{
|
||||
if (!is_valid_md5str(value))
|
||||
{
|
||||
THROW_MALERT("AIXMLElementParser_read_string_Invalid_MD5_VALUE_in_FILEDESC_FILENAME",
|
||||
AIArgs("[VALUE]", value)("[FILEDESC]", mFileDesc)("[FILENAME]", mFilename));
|
||||
}
|
||||
unsigned char digest[16];
|
||||
std::memset(digest, 0, sizeof(digest));
|
||||
for (int i = 0; i < 32; ++i)
|
||||
{
|
||||
int x = value[i];
|
||||
digest[i >> 1] += (x - (x & 0xf0) + (x >> 6) * 9) << ((~i & 1) << 2);
|
||||
}
|
||||
LLMD5 result;
|
||||
result.clone(digest);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<>
|
||||
LLDate AIXMLElementParser::read_string(std::string const& value) const
|
||||
{
|
||||
LLDate result;
|
||||
result.fromString(value);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T AIXMLElementParser::read_integer(char const* type, std::string const& value) const
|
||||
{
|
||||
long long int result;
|
||||
sscanf(value.c_str(),"%lld", &result);
|
||||
if (result < std::numeric_limits<T>::min() || result > std::numeric_limits<T>::max())
|
||||
{
|
||||
THROW_MALERT("AIXMLElementParser_read_integer_Invalid_TYPE_VALUE_in_FILEDESC_FILENAME",
|
||||
AIArgs("[TYPE]", type)("[VALUE]", value)("FILEDESC", mFileDesc)("[FILENAME]", mFilename));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<>
|
||||
U8 AIXMLElementParser::read_string(std::string const& value) const
|
||||
{
|
||||
return read_integer<U8>("U8", value);
|
||||
}
|
||||
|
||||
template<>
|
||||
S8 AIXMLElementParser::read_string(std::string const& value) const
|
||||
{
|
||||
return read_integer<S8>("S8", value);
|
||||
}
|
||||
|
||||
template<>
|
||||
U16 AIXMLElementParser::read_string(std::string const& value) const
|
||||
{
|
||||
return read_integer<U16>("U16", value);
|
||||
}
|
||||
|
||||
template<>
|
||||
S16 AIXMLElementParser::read_string(std::string const& value) const
|
||||
{
|
||||
return read_integer<S16>("S16", value);
|
||||
}
|
||||
|
||||
template<>
|
||||
U32 AIXMLElementParser::read_string(std::string const& value) const
|
||||
{
|
||||
return read_integer<U32>("U32", value);
|
||||
}
|
||||
|
||||
template<>
|
||||
S32 AIXMLElementParser::read_string(std::string const& value) const
|
||||
{
|
||||
return read_integer<S32>("S32", value);
|
||||
}
|
||||
|
||||
double read_float(std::string const& value)
|
||||
{
|
||||
double result;
|
||||
sscanf(value.c_str(),"%lf", &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<>
|
||||
F32 AIXMLElementParser::read_string(std::string const& value) const
|
||||
{
|
||||
return read_float(value);
|
||||
}
|
||||
|
||||
template<>
|
||||
F64 AIXMLElementParser::read_string(std::string const& value) const
|
||||
{
|
||||
return read_float(value);
|
||||
}
|
||||
|
||||
template<>
|
||||
bool AIXMLElementParser::read_string(std::string const& value) const
|
||||
{
|
||||
if (value == "true")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (value != "false")
|
||||
{
|
||||
THROW_MALERT("AIXMLElementParser_read_string_Invalid_boolean_VALUE_in_FILEDESC_FILENAME",
|
||||
AIArgs("[VALUE]", value)("FILEDESC]", mFileDesc)("[FILENAME]", mFilename));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AIXMLElementParser::attribute(char const* name, char const* required_value) const
|
||||
{
|
||||
char const* error = NULL;
|
||||
AIArgs args;
|
||||
std::string value;
|
||||
if (!mNode->getAttributeString(name, value))
|
||||
{
|
||||
error = "AIXMLElementParser_attribute_Missing_NAME_attribute_in_NODENAME_of_FILEDESC_FILENAME";
|
||||
}
|
||||
else if (value != required_value)
|
||||
{
|
||||
error = "AIXMLElementParser_attribute_Invalid_NAME_attribute_should_be_REQUIRED_in_NODENAME_of_FILEDESC_FILENAME";
|
||||
args("[REQUIRED]", required_value);
|
||||
}
|
||||
if (error)
|
||||
{
|
||||
THROW_MALERT(error, args("[NAME]", name)("[NODENAME]", node_name())("[FILEDESC]", mFileDesc)("[FILENAME]", mFilename));
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
LLUUID AIXMLElementParser::read_child(LLXmlTreeNode* node) const
|
||||
{
|
||||
LLUUID result;
|
||||
if (!LLUUID::parseUUID(node->getContents(), &result))
|
||||
{
|
||||
THROW_MALERT("AIXMLElementParser_read_child_Invalid_uuid_in_FILEDESC_FILENAME",
|
||||
AIArgs("[FILEDESC]", mFileDesc)("[FILENAME]", mFilename));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<>
|
||||
LLMD5 AIXMLElementParser::read_child(LLXmlTreeNode* node) const
|
||||
{
|
||||
return read_string<LLMD5>(node->getContents());
|
||||
}
|
||||
|
||||
template<>
|
||||
LLDate AIXMLElementParser::read_child(LLXmlTreeNode* node) const
|
||||
{
|
||||
LLDate result;
|
||||
if (!result.fromString(node->getContents()))
|
||||
{
|
||||
THROW_MALERT("AIXMLElementParser_read_child_Invalid_date_DATE_in_FILEDESC_FILENAME",
|
||||
AIArgs("[DATE]", node->getContents())("[FILEDESC]", mFileDesc)("[FILENAME]", mFilename));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<>
|
||||
S8 AIXMLElementParser::read_child(LLXmlTreeNode* node) const
|
||||
{
|
||||
return read_integer<S8>("S8", node->getContents());
|
||||
}
|
||||
|
||||
template<>
|
||||
U8 AIXMLElementParser::read_child(LLXmlTreeNode* node) const
|
||||
{
|
||||
return read_integer<U8>("U8", node->getContents());
|
||||
}
|
||||
|
||||
template<>
|
||||
S16 AIXMLElementParser::read_child(LLXmlTreeNode* node) const
|
||||
{
|
||||
return read_integer<S16>("S16", node->getContents());
|
||||
}
|
||||
|
||||
template<>
|
||||
U16 AIXMLElementParser::read_child(LLXmlTreeNode* node) const
|
||||
{
|
||||
return read_integer<U16>("U16", node->getContents());
|
||||
}
|
||||
|
||||
template<>
|
||||
S32 AIXMLElementParser::read_child(LLXmlTreeNode* node) const
|
||||
{
|
||||
return read_integer<S32>("S32", node->getContents());
|
||||
}
|
||||
|
||||
template<>
|
||||
U32 AIXMLElementParser::read_child(LLXmlTreeNode* node) const
|
||||
{
|
||||
return read_integer<U32>("U32", node->getContents());
|
||||
}
|
||||
|
||||
template<>
|
||||
F32 AIXMLElementParser::read_child(LLXmlTreeNode* node) const
|
||||
{
|
||||
return read_string<F32>(node->getContents());
|
||||
}
|
||||
|
||||
template<>
|
||||
F64 AIXMLElementParser::read_child(LLXmlTreeNode* node) const
|
||||
{
|
||||
return read_string<F64>(node->getContents());
|
||||
}
|
||||
|
||||
template<>
|
||||
bool AIXMLElementParser::read_child(LLXmlTreeNode* node) const
|
||||
{
|
||||
return read_string<bool>(node->getContents());
|
||||
}
|
||||
|
||||
bool AIXMLElementParser::child(LLUUID& uuid) const
|
||||
{
|
||||
return child(DEFAULT_LLUUID_NAME, uuid);
|
||||
}
|
||||
|
||||
bool AIXMLElementParser::child(LLMD5& md5) const
|
||||
{
|
||||
return child(DEFAULT_MD5STR_NAME, md5);
|
||||
}
|
||||
|
||||
bool AIXMLElementParser::child(LLDate& date) const
|
||||
{
|
||||
return child(DEFAULT_LLDATE_NAME, date);
|
||||
}
|
||||
|
||||
374
indra/llxml/aixml.h
Normal file
374
indra/llxml/aixml.h
Normal file
@@ -0,0 +1,374 @@
|
||||
/**
|
||||
* @file aixml.h
|
||||
* @brief XML serialization support.
|
||||
*
|
||||
* Copyright (c) 2013, Aleric Inglewood.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution.
|
||||
*
|
||||
* CHANGELOG
|
||||
* and additional copyright holders.
|
||||
*
|
||||
* 30/07/2013
|
||||
* Initial version, written by Aleric Inglewood @ SL
|
||||
*/
|
||||
|
||||
#ifndef AIXML_H
|
||||
#define AIXML_H
|
||||
|
||||
#include "llxmltree.h"
|
||||
#include "llxmlnode.h"
|
||||
#include "llfile.h"
|
||||
#include <sstream>
|
||||
#include "aialert.h"
|
||||
|
||||
extern char const* const DEFAULT_LLUUID_NAME;
|
||||
extern char const* const DEFAULT_MD5STR_NAME;
|
||||
extern char const* const DEFAULT_LLDATE_NAME;
|
||||
|
||||
class LLUUID;
|
||||
class LLMD5;
|
||||
class LLDate;
|
||||
|
||||
bool md5strFromXML(LLXmlTreeNode* node, std::string& md5str_out);
|
||||
bool md5strFromXML(LLXmlTreeNode* node, std::string& md5str_out, std::string const& attribute_name);
|
||||
bool UUIDFromXML(LLXmlTreeNode* node, LLUUID& uuid_out);
|
||||
bool UUIDFromXML(LLXmlTreeNode* node, LLUUID& uuid_out, std::string const& attribute_name);
|
||||
bool dateFromXML(LLXmlTreeNode* node, LLDate& date_out);
|
||||
bool dateFromXML(LLXmlTreeNode* node, LLDate& date_out, std::string const& attribute_name);
|
||||
bool versionFromXML(LLXmlTreeNode* node, U32& major_out, U32& minor_out);
|
||||
bool versionFromXML(LLXmlTreeNode* node, U32& major_out, U32& minor_out, std::string const& attribute_name);
|
||||
|
||||
class AIXMLElement
|
||||
{
|
||||
private:
|
||||
std::ostream& mOs;
|
||||
std::string mName;
|
||||
int mIndentation;
|
||||
bool mHasChildren;
|
||||
|
||||
public:
|
||||
AIXMLElement(std::ostream& os, char const* name, int indentation);
|
||||
~AIXMLElement();
|
||||
|
||||
template<typename T>
|
||||
void attribute(char const* name, T const& attribute);
|
||||
template<typename T>
|
||||
void child(T const& element);
|
||||
template<typename T>
|
||||
void child(char const* name, T const& element);
|
||||
template<typename FWD_ITERATOR>
|
||||
void child(FWD_ITERATOR i1, FWD_ITERATOR const& i2);
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
void write_child(char const* name, T const& element);
|
||||
|
||||
int open_child(void);
|
||||
void close_child(void);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
void AIXMLElement::attribute(char const* name, T const& attribute)
|
||||
{
|
||||
std::ostringstream raw_attribute;
|
||||
raw_attribute << attribute;
|
||||
mOs << ' ' << name << "=\"" << LLXMLNode::escapeXML(raw_attribute.str()) << '"';
|
||||
if (!mOs.good())
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << ' ' << name << "=\"" << LLXMLNode::escapeXML(raw_attribute.str()) << '"';
|
||||
THROW_FALERT("AIXMLElement_attribute_Failed_to_write_DATA", AIArgs("[DATA]", ss.str()));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void AIXMLElement::child(T const& element)
|
||||
{
|
||||
open_child();
|
||||
element.toXML(mOs, mIndentation);
|
||||
if (!mOs.good()) // Normally toXML will already have thrown.
|
||||
{
|
||||
THROW_FALERT("AIXMLElement_child_Bad_ostream");
|
||||
}
|
||||
close_child();
|
||||
}
|
||||
|
||||
template<>
|
||||
void AIXMLElement::child(LLUUID const& element);
|
||||
|
||||
template<>
|
||||
void AIXMLElement::child(LLMD5 const& element);
|
||||
|
||||
template<>
|
||||
void AIXMLElement::child(LLDate const& element);
|
||||
|
||||
template<typename T>
|
||||
void AIXMLElement::write_child(char const* name, T const& element)
|
||||
{
|
||||
mOs << std::string(mIndentation, ' ') << '<' << name << '>' << element << "</" << name << ">\n";
|
||||
if (!mOs.good())
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << std::string(mIndentation, ' ') << '<' << name << '>' << element << "</" << name << ">\\n";
|
||||
THROW_FALERT("AIXMLElement_write_child_Failed_to_write_DATA", AIArgs("[DATA]", ss.str()));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void AIXMLElement::child(char const* name, T const& element)
|
||||
{
|
||||
open_child();
|
||||
write_child(name, element);
|
||||
close_child();
|
||||
}
|
||||
|
||||
template<typename FWD_ITERATOR>
|
||||
void AIXMLElement::child(FWD_ITERATOR i1, FWD_ITERATOR const& i2)
|
||||
{
|
||||
while (i1 != i2)
|
||||
{
|
||||
child(*i1++);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper class for AIXMLRootElement.
|
||||
class AIXMLStream {
|
||||
protected:
|
||||
llofstream mOfs;
|
||||
AIXMLStream(LLFILE* fp, bool standalone);
|
||||
~AIXMLStream();
|
||||
};
|
||||
|
||||
// Class to write XML files.
|
||||
class AIXMLRootElement : public AIXMLStream, public AIXMLElement
|
||||
{
|
||||
public:
|
||||
AIXMLRootElement(LLFILE* fp, char const* name, bool standalone = true) : AIXMLStream(fp, standalone), AIXMLElement(mOfs, name, 0) { }
|
||||
};
|
||||
|
||||
class AIXMLElementParser
|
||||
{
|
||||
private:
|
||||
U32 mVersion;
|
||||
std::string const& mFilename;
|
||||
std::string const& mFileDesc;
|
||||
|
||||
protected:
|
||||
LLXmlTreeNode* mNode;
|
||||
|
||||
protected:
|
||||
// Used by AIXMLParser, which initializes mNode directly.
|
||||
AIXMLElementParser(std::string const& filename, std::string const& file_desc, U32 version) : mVersion(version), mFilename(filename), mFileDesc(file_desc) { }
|
||||
|
||||
// Used for error reporting.
|
||||
virtual std::string node_name(void) const { return "node '" + mNode->getName() + "'"; }
|
||||
|
||||
// Parse the integer given as string 'value' and return it as type T (U8, S8, U16, S16, U32 or S32).
|
||||
template<typename T>
|
||||
T read_integer(char const* type, std::string const& value) const;
|
||||
|
||||
// Parse the string 'value' and return it as type T.
|
||||
template<typename T>
|
||||
T read_string(std::string const& value) const;
|
||||
|
||||
// Parse a child node and return it as type T.
|
||||
template<typename T>
|
||||
T read_child(LLXmlTreeNode* node) const;
|
||||
|
||||
public:
|
||||
// Constructor for child member functions.
|
||||
AIXMLElementParser(std::string const& filename, std::string const& file_desc, U32 version, LLXmlTreeNode* node) : mVersion(version), mFilename(filename), mFileDesc(file_desc), mNode(node) { }
|
||||
|
||||
// Require the existence of some attribute with given value.
|
||||
void attribute(char const* name, char const* required_value) const;
|
||||
|
||||
// Read attribute. Returns true if attribute was found.
|
||||
template<typename T>
|
||||
bool attribute(char const* name, T& attribute) const;
|
||||
|
||||
// Read child element. Returns true if child was found.
|
||||
template<typename T>
|
||||
bool child(char const* name, T& child) const;
|
||||
// Read Linden types. Return true if the child was found.
|
||||
bool child(LLUUID& uuid) const;
|
||||
bool child(LLMD5& md5) const;
|
||||
bool child(LLDate& date) const;
|
||||
|
||||
// Append all elements with name 'name' to container.
|
||||
template<typename CONTAINER>
|
||||
void push_back_children(char const* name, CONTAINER& container) const;
|
||||
|
||||
// Insert all elements with name 'name' into container.
|
||||
template<typename CONTAINER>
|
||||
void insert_children(char const* name, CONTAINER& container) const;
|
||||
|
||||
// Set version of this particular element (if not set mVersion will be the version of the parent, all the way up to the xml header with a version of 1).
|
||||
void setVersion(U32 version) { mVersion = version; }
|
||||
|
||||
// Accessors.
|
||||
std::string const& filename(void) const { return mFilename; }
|
||||
std::string const& filedesc(void) const { return mFileDesc; }
|
||||
U32 version(void) const { return mVersion; }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline T AIXMLElementParser::read_string(std::string const& value) const
|
||||
{
|
||||
// Construct from string.
|
||||
return T(value);
|
||||
}
|
||||
|
||||
// Specializations.
|
||||
|
||||
template<>
|
||||
LLMD5 AIXMLElementParser::read_string(std::string const& value) const;
|
||||
|
||||
template<>
|
||||
LLDate AIXMLElementParser::read_string(std::string const& value) const;
|
||||
|
||||
template<>
|
||||
U8 AIXMLElementParser::read_string(std::string const& value) const;
|
||||
|
||||
template<>
|
||||
S8 AIXMLElementParser::read_string(std::string const& value) const;
|
||||
|
||||
template<>
|
||||
U16 AIXMLElementParser::read_string(std::string const& value) const;
|
||||
|
||||
template<>
|
||||
S16 AIXMLElementParser::read_string(std::string const& value) const;
|
||||
|
||||
template<>
|
||||
U32 AIXMLElementParser::read_string(std::string const& value) const;
|
||||
|
||||
template<>
|
||||
S32 AIXMLElementParser::read_string(std::string const& value) const;
|
||||
|
||||
template<>
|
||||
F32 AIXMLElementParser::read_string(std::string const& value) const;
|
||||
|
||||
template<>
|
||||
F64 AIXMLElementParser::read_string(std::string const& value) const;
|
||||
|
||||
template<>
|
||||
bool AIXMLElementParser::read_string(std::string const& value) const;
|
||||
|
||||
|
||||
template<typename T>
|
||||
bool AIXMLElementParser::attribute(char const* name, T& attribute) const
|
||||
{
|
||||
std::string value;
|
||||
if (!mNode->getAttributeString(name, value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
attribute = read_string<T>(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T AIXMLElementParser::read_child(LLXmlTreeNode* node) const
|
||||
{
|
||||
return AIXMLElementParser(mFilename, mFileDesc, mVersion, node);
|
||||
}
|
||||
|
||||
// Specializations.
|
||||
|
||||
template<>
|
||||
inline std::string AIXMLElementParser::read_child(LLXmlTreeNode* node) const
|
||||
{
|
||||
return node->getContents();
|
||||
}
|
||||
|
||||
template<>
|
||||
LLMD5 AIXMLElementParser::read_child(LLXmlTreeNode* node) const;
|
||||
|
||||
template<>
|
||||
LLUUID AIXMLElementParser::read_child(LLXmlTreeNode* node) const;
|
||||
|
||||
template<>
|
||||
LLDate AIXMLElementParser::read_child(LLXmlTreeNode* node) const;
|
||||
|
||||
template<>
|
||||
S32 AIXMLElementParser::read_child(LLXmlTreeNode* node) const;
|
||||
|
||||
template<>
|
||||
F32 AIXMLElementParser::read_child(LLXmlTreeNode* node) const;
|
||||
|
||||
template<>
|
||||
bool AIXMLElementParser::read_child(LLXmlTreeNode* node) const;
|
||||
|
||||
|
||||
template<typename T>
|
||||
bool AIXMLElementParser::child(char const* name, T& child) const
|
||||
{
|
||||
LLXmlTreeNode* node = mNode->getChildByName(name);
|
||||
if (!node)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
child = read_child<T>(node);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename CONTAINER>
|
||||
void AIXMLElementParser::insert_children(char const* name, CONTAINER& container) const
|
||||
{
|
||||
for (LLXmlTreeNode* node = mNode->getFirstChild(); node; node = mNode->getNextChild())
|
||||
{
|
||||
if (!node->hasName(name))
|
||||
continue;
|
||||
container.insert(read_child<typename CONTAINER::value_type>(node));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename CONTAINER>
|
||||
void AIXMLElementParser::push_back_children(char const* name, CONTAINER& container) const
|
||||
{
|
||||
for (LLXmlTreeNode* node = mNode->getFirstChild(); node; node = mNode->getNextChild())
|
||||
{
|
||||
if (!node->hasName(name))
|
||||
continue;
|
||||
container.push_back(read_child<typename CONTAINER::value_type>(node));
|
||||
}
|
||||
}
|
||||
|
||||
// Class to read XML files.
|
||||
class AIXMLParser : public AIXMLElementParser
|
||||
{
|
||||
private:
|
||||
std::string mFilename;
|
||||
std::string mFileDesc;
|
||||
|
||||
LLXmlTree mXmlTree;
|
||||
U32 mVersionMajor;
|
||||
U32 mVersionMinor;
|
||||
|
||||
public:
|
||||
AIXMLParser(std::string const& filename, char const* file_desc, std::string const& name, U32 major_version);
|
||||
|
||||
U32 version_major(void) const { return mVersionMajor; }
|
||||
U32 version_minor(void) const { return mVersionMinor; }
|
||||
|
||||
protected:
|
||||
/*virtual*/ std::string node_name(void) const { return "root node"; }
|
||||
};
|
||||
|
||||
#endif // AIXML_H
|
||||
|
||||
@@ -555,6 +555,36 @@ void XMLCALL EndXMLNode(void *userData,
|
||||
node->setValue(value);
|
||||
}
|
||||
}
|
||||
// Singu note: moved here from XMLData.
|
||||
if (LLXMLNode::sStripEscapedStrings)
|
||||
{
|
||||
std::string value = node->getValue();
|
||||
int len = value.length();
|
||||
if (len > 1 && value[0] == '"' && value[len - 1] == '"')
|
||||
{
|
||||
// Special-case: Escaped string.
|
||||
std::string unescaped_string;
|
||||
for (S32 pos = 1; pos < len - 1; ++pos)
|
||||
{
|
||||
if (value[pos] == '\\' && value[pos + 1] == '\\')
|
||||
{
|
||||
unescaped_string += '\\';
|
||||
++pos;
|
||||
}
|
||||
else if (value[pos] == '\\' && value[pos + 1] == '"')
|
||||
{
|
||||
unescaped_string += '"';
|
||||
++pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
unescaped_string += value[pos];
|
||||
}
|
||||
}
|
||||
value += unescaped_string;
|
||||
node->setValue(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void XMLCALL XMLData(void *userData,
|
||||
@@ -563,6 +593,15 @@ void XMLCALL XMLData(void *userData,
|
||||
{
|
||||
LLXMLNode* current_node = (LLXMLNode *)userData;
|
||||
std::string value = current_node->getValue();
|
||||
#if 0
|
||||
// Apparently also Lindens who write XML parsers can't read documentation.
|
||||
// "A single block of contiguous text free of markup may still result in a sequence
|
||||
// of calls to this handler. In other words, if you're searching for a pattern in
|
||||
// the text, it may be split across calls to this handler."
|
||||
// (http://sepp.oetiker.ch/expat-1.95.6-rs.SEPP/expat-1.95.6/doc/reference.html#XML_SetCharacterDataHandler)
|
||||
//
|
||||
// In other words, this is not guaranteed to work at all -- Aleric.
|
||||
|
||||
if (LLXMLNode::sStripEscapedStrings)
|
||||
{
|
||||
if (s[0] == '\"' && s[len-1] == '\"')
|
||||
@@ -591,6 +630,7 @@ void XMLCALL XMLData(void *userData,
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
value.append(std::string(s, len));
|
||||
current_node->setValue(value);
|
||||
}
|
||||
@@ -928,12 +968,6 @@ bool LLXMLNode::getLayeredXMLNode(LLXMLNodePtr& root,
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
void LLXMLNode::writeHeaderToFile(LLFILE *out_file)
|
||||
{
|
||||
fprintf(out_file, "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\" ?>\n");
|
||||
}
|
||||
|
||||
void LLXMLNode::writeToFile(LLFILE *out_file, const std::string& indent, bool use_type_decorations)
|
||||
{
|
||||
if (isFullyDefault())
|
||||
|
||||
@@ -157,11 +157,6 @@ public:
|
||||
|
||||
static bool getLayeredXMLNode(LLXMLNodePtr& root, const std::vector<std::string>& paths);
|
||||
|
||||
|
||||
// Write standard XML file header:
|
||||
// <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
|
||||
static void writeHeaderToFile(LLFILE *out_file);
|
||||
|
||||
// Write XML to file with one attribute per line.
|
||||
// XML escapes values as they are written.
|
||||
void writeToFile(LLFILE *out_file, const std::string& indent = std::string(), bool use_type_decorations=true);
|
||||
|
||||
@@ -82,6 +82,7 @@ include_directories(
|
||||
set(viewer_SOURCE_FILES
|
||||
NACLantispam.cpp
|
||||
aihttpview.cpp
|
||||
aixmllindengenepool.cpp
|
||||
aoremotectrl.cpp
|
||||
ascentfloatercontactgroups.cpp
|
||||
ascentkeyword.cpp
|
||||
@@ -599,6 +600,7 @@ set(viewer_HEADER_FILES
|
||||
|
||||
NACLantispam.h
|
||||
aihttpview.h
|
||||
aixmllindengenepool.h
|
||||
aoremotectrl.h
|
||||
ascentfloatercontactgroups.h
|
||||
ascentkeyword.h
|
||||
|
||||
205
indra/newview/aixmllindengenepool.cpp
Normal file
205
indra/newview/aixmllindengenepool.cpp
Normal file
@@ -0,0 +1,205 @@
|
||||
/**
|
||||
* @file aixmllindengenepool.cpp
|
||||
* @brief XML linden_genepool serialization support.
|
||||
*
|
||||
* Copyright (c) 2013, Aleric Inglewood.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution.
|
||||
*
|
||||
* CHANGELOG
|
||||
* and additional copyright holders.
|
||||
*
|
||||
* 01/11/2013
|
||||
* Initial version, written by Aleric Inglewood @ SL
|
||||
*/
|
||||
|
||||
// metaversion 1.0
|
||||
// ===============
|
||||
//
|
||||
// Added as child of <linden_genepool>:
|
||||
//
|
||||
// <meta gridnick="secondlife" date="2013-07-16T16:49:00.40Z" />
|
||||
//
|
||||
// Optionally, as child of <archetype>, the following node may appear:
|
||||
//
|
||||
// <meta path="clothing/jackets" name="Purple jacket" description="A jacket with mainly the color purple" />
|
||||
//
|
||||
// Furthermore, metaversion 1.0 and higher allow the occurance of one or more <archetype> blocks.
|
||||
// If this is used then it is strongly advised to use one <archetype> per wearable, so that
|
||||
// the the <meta> node makes sense (it then refers to the wearable of that <archetype>).
|
||||
//
|
||||
// The reason for this clumsy way to link wearable to extra meta data is to stay
|
||||
// compatible with the older format (no metaversion).
|
||||
|
||||
#include "sys.h"
|
||||
#include "aixmllindengenepool.h"
|
||||
#include "hippogridmanager.h"
|
||||
#include "llvisualparam.h"
|
||||
#include "llviewerwearable.h"
|
||||
#include "llquantize.h"
|
||||
|
||||
extern void append_path_short(LLUUID const& id, std::string& path);
|
||||
|
||||
void AIXMLLindenGenepool::MetaData::toXML(std::ostream& os, int indentation) const
|
||||
{
|
||||
AIXMLElement tag(os, "meta", indentation);
|
||||
tag.attribute("gridnick", mGridNick);
|
||||
tag.attribute(DEFAULT_LLDATE_NAME, mDate);
|
||||
}
|
||||
|
||||
AIXMLLindenGenepool::MetaData::MetaData(AIXMLElementParser const& parser)
|
||||
{
|
||||
parser.attribute("gridnick", mGridNick);
|
||||
parser.attribute(DEFAULT_LLDATE_NAME, mDate);
|
||||
}
|
||||
|
||||
AIXMLLindenGenepool::AIXMLLindenGenepool(LLFILE* fp) : AIXMLRootElement(fp, "linden_genepool")
|
||||
{
|
||||
attribute("version", "1.0");
|
||||
attribute("metaversion", "1.0");
|
||||
child(MetaData(gHippoGridManager->getConnectedGrid()->getGridNick(), LLDate::now()));
|
||||
}
|
||||
|
||||
void AIVisualParamIDValuePair::toXML(std::ostream& os, int indentation) const
|
||||
{
|
||||
LLVisualParam const* visual_param = mVisualParam;
|
||||
if (!visual_param && mWearable)
|
||||
{
|
||||
visual_param = mWearable->getVisualParam(mID);
|
||||
}
|
||||
if (visual_param)
|
||||
{
|
||||
AIXMLElement tag(os, "param", indentation);
|
||||
tag.attribute("id", mID);
|
||||
tag.attribute("name", visual_param->getName());
|
||||
tag.attribute("value", mValue);
|
||||
tag.attribute("u8", (U32)F32_to_U8(mValue, visual_param->getMinWeight(), visual_param->getMaxWeight()));
|
||||
tag.attribute("type", visual_param->getTypeString());
|
||||
tag.attribute("wearable", visual_param->getDumpWearableTypeName());
|
||||
}
|
||||
}
|
||||
|
||||
AIVisualParamIDValuePair::AIVisualParamIDValuePair(AIXMLElementParser const& parser)
|
||||
{
|
||||
// Only id and value are relevant. Ignore all other attributes.
|
||||
parser.attribute("id", mID);
|
||||
parser.attribute("value", mValue);
|
||||
}
|
||||
|
||||
void AITextureIDUUIDPair::toXML(std::ostream& os, int indentation) const
|
||||
{
|
||||
AIXMLElement tag(os, "texture", indentation);
|
||||
tag.attribute("te", mID);
|
||||
tag.attribute(DEFAULT_LLUUID_NAME, mUUID);
|
||||
}
|
||||
|
||||
AITextureIDUUIDPair::AITextureIDUUIDPair(AIXMLElementParser const& parser)
|
||||
{
|
||||
parser.attribute("te", mID);
|
||||
parser.attribute(DEFAULT_LLUUID_NAME, mUUID);
|
||||
}
|
||||
|
||||
void AIArchetype::MetaData::toXML(std::ostream& os, int indentation) const
|
||||
{
|
||||
AIXMLElement tag(os, "meta", indentation);
|
||||
tag.attribute("path", mPath);
|
||||
tag.attribute("name", mName);
|
||||
tag.attribute("description", mDescription);
|
||||
}
|
||||
|
||||
AIArchetype::MetaData::MetaData(AIXMLElementParser const& parser)
|
||||
{
|
||||
char const* missing = NULL;
|
||||
if (!parser.attribute("path", mPath))
|
||||
{
|
||||
missing = "path";
|
||||
}
|
||||
if (!parser.attribute("name", mName))
|
||||
{
|
||||
missing = "name";
|
||||
}
|
||||
if (!parser.attribute("description", mDescription))
|
||||
{
|
||||
missing = "description";
|
||||
}
|
||||
if (missing)
|
||||
{
|
||||
THROW_ALERT("AIArchetype_MetaData_archetype_meta_has_no_ATTRIBUTE", AIArgs("[ATTRIBUTE]", missing));
|
||||
}
|
||||
}
|
||||
|
||||
AIArchetype::MetaData::MetaData(LLViewerWearable const* wearable) : mName(wearable->getName()), mDescription(wearable->getDescription())
|
||||
{
|
||||
append_path_short(wearable->getItemID(), mPath);
|
||||
}
|
||||
|
||||
AIArchetype::AIArchetype(void) : mType(LLWearableType::WT_NONE)
|
||||
{
|
||||
}
|
||||
|
||||
AIArchetype::AIArchetype(LLWearableType::EType type) : mType(type)
|
||||
{
|
||||
}
|
||||
|
||||
AIArchetype::AIArchetype(LLViewerWearable const* wearable) : mType(wearable->getType()), mMetaData(wearable)
|
||||
{
|
||||
}
|
||||
|
||||
void AIArchetype::toXML(std::ostream& os, int indentation) const
|
||||
{
|
||||
AIXMLElement tag(os, "archetype", indentation);
|
||||
if (mType == LLWearableType::WT_NONE)
|
||||
{
|
||||
tag.attribute("name", "???");
|
||||
}
|
||||
else
|
||||
{
|
||||
tag.attribute("name", LLWearableType::getTypeName(mType));
|
||||
}
|
||||
if (!mMetaData.mPath.empty())
|
||||
{
|
||||
tag.child(mMetaData);
|
||||
}
|
||||
tag.child(mParams.begin(), mParams.end());
|
||||
tag.child(mTextures.begin(), mTextures.end());
|
||||
}
|
||||
|
||||
AIArchetype::AIArchetype(AIXMLElementParser const& parser)
|
||||
{
|
||||
std::string name;
|
||||
mType = LLWearableType::WT_NONE;
|
||||
|
||||
if (!parser.attribute("name", name))
|
||||
{
|
||||
llwarns << "The <archetype> tag in file \"" << parser.filename() << "\" is missing the 'name' parameter." << llendl;
|
||||
}
|
||||
else if (name != "???")
|
||||
{
|
||||
mType = LLWearableType::typeNameToType(name);
|
||||
}
|
||||
if (parser.version() >= 1)
|
||||
{
|
||||
if (!parser.child("meta", mMetaData))
|
||||
{
|
||||
THROW_ALERT("AIArchetype_archetype_has_no_meta");
|
||||
}
|
||||
}
|
||||
parser.push_back_children("param", mParams);
|
||||
parser.push_back_children("texture", mTextures);
|
||||
}
|
||||
|
||||
150
indra/newview/aixmllindengenepool.h
Normal file
150
indra/newview/aixmllindengenepool.h
Normal file
@@ -0,0 +1,150 @@
|
||||
/**
|
||||
* @file aixmllindengenepool.h
|
||||
* @brief XML linden_genepool serialization support.
|
||||
*
|
||||
* Copyright (c) 2013, Aleric Inglewood.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution.
|
||||
*
|
||||
* CHANGELOG
|
||||
* and additional copyright holders.
|
||||
*
|
||||
* 01/11/2013
|
||||
* Initial version, written by Aleric Inglewood @ SL
|
||||
*/
|
||||
|
||||
#ifndef AIXMLLINDENGENEPOOL_H
|
||||
#define AIXMLLINDENGENEPOOL_H
|
||||
|
||||
#include "aixml.h"
|
||||
#include "llwearabletype.h"
|
||||
#include "llviewervisualparam.h"
|
||||
#include <vector>
|
||||
|
||||
class LLViewerWearable;
|
||||
|
||||
class AIXMLLindenGenepool : public AIXMLRootElement
|
||||
{
|
||||
public:
|
||||
struct MetaData
|
||||
{
|
||||
std::string mGridNick;
|
||||
LLDate mDate;
|
||||
|
||||
MetaData(void) { }
|
||||
MetaData(std::string const& grid_nick, LLDate const& date) : mGridNick(grid_nick), mDate(date) { }
|
||||
|
||||
void toXML(std::ostream& os, int indentation) const;
|
||||
MetaData(AIXMLElementParser const& parser);
|
||||
};
|
||||
|
||||
AIXMLLindenGenepool(LLFILE* fp);
|
||||
};
|
||||
|
||||
class AIVisualParamIDValuePair
|
||||
{
|
||||
private:
|
||||
// A wearable + ID define the LLVisualParam, but it also possible to specify the LLVisualParam directly.
|
||||
LLVisualParam const* mVisualParam; // Specific LLVisualParam, given at construction, or ...
|
||||
LLViewerWearable const* mWearable; // Underlaying wearable, if any.
|
||||
|
||||
U32 mID; // The visual parameter id.
|
||||
F32 mValue; // The value of the visual parameter.
|
||||
|
||||
public:
|
||||
AIVisualParamIDValuePair(LLVisualParam const* visual_param) :
|
||||
mVisualParam(visual_param), mWearable(NULL), mID(visual_param->getID()), mValue(visual_param->getWeight()) { }
|
||||
|
||||
AIVisualParamIDValuePair(LLVisualParam const* visual_param, F32 value) :
|
||||
mVisualParam(visual_param), mWearable(NULL), mID(visual_param->getID()), mValue(value) { }
|
||||
|
||||
AIVisualParamIDValuePair(LLViewerWearable const* wearable, U32 id, F32 value) :
|
||||
mVisualParam(NULL), mWearable(wearable), mID(id), mValue(value) { }
|
||||
|
||||
void toXML(std::ostream& os, int indentation) const;
|
||||
AIVisualParamIDValuePair(AIXMLElementParser const& parser);
|
||||
|
||||
// Accessors.
|
||||
U32 getID(void) const { return mID; }
|
||||
F32 getValue(void) const { return mValue; }
|
||||
};
|
||||
|
||||
class AITextureIDUUIDPair
|
||||
{
|
||||
private:
|
||||
U32 mID;
|
||||
LLUUID mUUID;
|
||||
|
||||
public:
|
||||
AITextureIDUUIDPair(U32 id, LLUUID const& uuid) : mID(id), mUUID(uuid) { }
|
||||
|
||||
void toXML(std::ostream& os, int indentation) const;
|
||||
AITextureIDUUIDPair(AIXMLElementParser const& parser);
|
||||
|
||||
// Accessors.
|
||||
U32 getID(void) const { return mID; }
|
||||
LLUUID const& getUUID(void) const { return mUUID; }
|
||||
};
|
||||
|
||||
class AIArchetype
|
||||
{
|
||||
public:
|
||||
struct MetaData
|
||||
{
|
||||
std::string mPath; // The wearable location in the inventory.
|
||||
std::string mName; // The wearable name.
|
||||
std::string mDescription; // The wearable description.
|
||||
|
||||
MetaData(void) { }
|
||||
MetaData(LLViewerWearable const* wearable);
|
||||
|
||||
void toXML(std::ostream& os, int indentation) const;
|
||||
MetaData(AIXMLElementParser const& parser);
|
||||
};
|
||||
|
||||
typedef std::vector<AIVisualParamIDValuePair> params_type;
|
||||
typedef std::vector<AITextureIDUUIDPair> textures_type;
|
||||
|
||||
private:
|
||||
LLWearableType::EType mType; // The type of the wearable.
|
||||
MetaData mMetaData;
|
||||
params_type mParams;
|
||||
textures_type mTextures;
|
||||
|
||||
public:
|
||||
// Accessors.
|
||||
LLWearableType::EType getType(void) const { return mType; }
|
||||
MetaData const& getMetaData(void) const { return mMetaData; }
|
||||
params_type const& getParams(void) const { return mParams; }
|
||||
textures_type const& getTextures(void) const { return mTextures; }
|
||||
|
||||
public:
|
||||
// An archtype without wearable has no (known) metadata. This is recognized because mPath will be empty.
|
||||
// An archtype without type with get the attribute name="???".
|
||||
AIArchetype(void); // <archetype name="???">
|
||||
AIArchetype(LLWearableType::EType type); // <archetype name="shirt">
|
||||
AIArchetype(LLViewerWearable const* wearable); // <archetype name="shirt"> <meta path="myclothes" name="blue shirt" description="Awesome blue shirt">
|
||||
|
||||
void add(AIVisualParamIDValuePair const& visual_param_id_value_pair) { mParams.push_back(visual_param_id_value_pair); }
|
||||
void add(AITextureIDUUIDPair const& texture_id_uuid_pair) { mTextures.push_back(texture_id_uuid_pair); }
|
||||
|
||||
void toXML(std::ostream& os, int indentation) const;
|
||||
AIArchetype(AIXMLElementParser const& parser);
|
||||
};
|
||||
|
||||
#endif // AIXMLLINDENGENEPOOL_H
|
||||
@@ -53,8 +53,9 @@
|
||||
#include "llvoavatarself.h"
|
||||
|
||||
#include "statemachine/aifilepicker.h"
|
||||
#include "llxmltree.h"
|
||||
#include "hippogridmanager.h"
|
||||
#include "aixmllindengenepool.h"
|
||||
#include "aifile.h"
|
||||
|
||||
using namespace LLAvatarAppearanceDefines;
|
||||
|
||||
@@ -330,215 +331,112 @@ void LLFloaterCustomize::onBtnImport_continued(AIFilePicker* filepicker)
|
||||
LLPanelEditWearable* panel_edit_wearable = getCurrentWearablePanel();
|
||||
LLViewerWearable* edit_wearable = panel_edit_wearable->getWearable();
|
||||
|
||||
LLWearableType::EType panel_wearable_type = panel_edit_wearable->getType();
|
||||
std::string label = utf8str_tolower(panel_edit_wearable->getLabel());
|
||||
|
||||
std::string const filename = filepicker->getFilename();
|
||||
LLSD args(LLSD::emptyMap());
|
||||
args["FILE"] = gDirUtilp->getBaseFileName(filename);
|
||||
|
||||
LLXmlTree xml;
|
||||
BOOL success = xml.parseFile(filename, FALSE);
|
||||
if (!success)
|
||||
{
|
||||
LLNotificationsUtil::add("AIXMLImportParseError", args);
|
||||
return;
|
||||
}
|
||||
LLXmlTreeNode* root = xml.getRoot();
|
||||
if (!root)
|
||||
{
|
||||
llwarns << "No root node found in wearable import file: " << filename << llendl;
|
||||
LLNotificationsUtil::add("AIXMLImportParseError", args);
|
||||
return;
|
||||
}
|
||||
AIArgs args("[FILE]", gDirUtilp->getBaseFileName(filename));
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// <linden_genepool version="1.0" [metaversion="?"]> (root)
|
||||
//-------------------------------------------------------------------------
|
||||
if (!root->hasName("linden_genepool"))
|
||||
{
|
||||
llwarns << "Invalid wearable import file (missing linden_genepool header): " << filename << llendl;
|
||||
LLNotificationsUtil::add("AIXMLImportRootTypeError", args);
|
||||
return;
|
||||
}
|
||||
static LLStdStringHandle const version_string = LLXmlTree::addAttributeString("version");
|
||||
std::string version;
|
||||
if (!root->getFastAttributeString(version_string, version) || (version != "1.0"))
|
||||
{
|
||||
llwarns << "Invalid or incompatible linden_genepool version: " << version << " in file: " << filename << llendl;
|
||||
args["TAG"] = "version";
|
||||
args["VERSIONMAJOR"] = "1";
|
||||
LLNotificationsUtil::add("AIXMLImportRootVersionError", args);
|
||||
return;
|
||||
}
|
||||
static LLStdStringHandle const metaversion_string = LLXmlTree::addAttributeString("metaversion");
|
||||
std::string metaversion;
|
||||
U32 metaversion_major;
|
||||
if (!root->getFastAttributeString(metaversion_string, metaversion))
|
||||
{
|
||||
llwarns << "Invalid linden_genepool metaversion: " << metaversion << " in file: " << filename << llendl;
|
||||
metaversion_major = 0;
|
||||
}
|
||||
else if (!LLStringUtil::convertToU32(metaversion, metaversion_major) || metaversion_major > 1)
|
||||
{
|
||||
llwarns << "Invalid or incompatible linden_genepool metaversion: " << metaversion << " in file: " << filename << llendl;
|
||||
args["TAG"] = "metaversion";
|
||||
args["VERSIONMAJOR"] = "1";
|
||||
LLNotificationsUtil::add("AIXMLImportRootVersionError", args);
|
||||
return;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// <meta gridnick="secondlife" date="2013-07-20T15:27:55.80Z">
|
||||
//-------------------------------------------------------------------------
|
||||
std::string gridnick;
|
||||
LLDate date;
|
||||
bool different_grid = false; // By default assume it was exported on the same grid as we're on now.
|
||||
bool mixed_grids = false; // Set to true if two different grids (might) share UUIDs. Currently only "secondlife" and "secondlife_beta".
|
||||
if (metaversion_major >= 1)
|
||||
{
|
||||
static LLStdStringHandle const gridnick_string = LLXmlTree::addAttributeString("gridnick");
|
||||
static LLStdStringHandle const date_string = LLXmlTree::addAttributeString("date");
|
||||
std::string date_s;
|
||||
bool invalid = true;
|
||||
LLXmlTreeNode* meta_node = root->getChildByName("meta");
|
||||
if (!meta_node)
|
||||
{
|
||||
llwarns << "No meta (1) in wearable import file: " << filename << llendl;
|
||||
}
|
||||
else if (!meta_node->getFastAttributeString(gridnick_string, gridnick))
|
||||
{
|
||||
llwarns << "meta tag in file: " << filename << " is missing the 'gridnick' parameter." << llendl;
|
||||
}
|
||||
else if (!meta_node->getFastAttributeString(date_string, date_s) || !date.fromString(date_s))
|
||||
{
|
||||
llwarns << "meta tag in file: " << filename << " is missing or invalid 'date' parameter." << llendl;
|
||||
}
|
||||
else
|
||||
{
|
||||
invalid = false;
|
||||
std::string current_gridnick = gHippoGridManager->getConnectedGrid()->getGridNick();
|
||||
different_grid = gridnick != current_gridnick;
|
||||
mixed_grids = (gridnick == "secondlife" && current_gridnick == "secondlife_beta") ||
|
||||
(gridnick == "secondlife_beta" && current_gridnick == "secondlife");
|
||||
}
|
||||
if (invalid)
|
||||
{
|
||||
LLNotificationsUtil::add("AIXMLImportInvalidError", args);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static LLStdStringHandle const name_string = LLXmlTree::addAttributeString("name");
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// <archetype name="???">
|
||||
//-------------------------------------------------------------------------
|
||||
LLXmlTreeNode* archetype_node = root->getChildByName("archetype");
|
||||
if (!archetype_node)
|
||||
{
|
||||
llwarns << "No archetype in wearable import file: " << filename << llendl;
|
||||
LLNotificationsUtil::add("AIXMLImportInvalidError", args);
|
||||
return;
|
||||
}
|
||||
// Legacy that name="" exists. Using it as human (only) readable type label of contents. Don't use it for anything else because it might not be set.
|
||||
std::string label = "???";
|
||||
if (metaversion_major >= 1)
|
||||
{
|
||||
if (!archetype_node->getFastAttributeString(name_string, label))
|
||||
{
|
||||
llwarns << "archetype tag in file: " << filename << " is missing the 'name' parameter." << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// <meta path="Clothing" name="New Shirt27" description="Some description"/>
|
||||
//-------------------------------------------------------------------------
|
||||
std::string path;
|
||||
std::string wearable_name;
|
||||
std::string wearable_description;
|
||||
if (metaversion_major >= 1)
|
||||
{
|
||||
static LLStdStringHandle const path_string = LLXmlTree::addAttributeString("path");
|
||||
static LLStdStringHandle const description_string = LLXmlTree::addAttributeString("description");
|
||||
bool invalid = true;
|
||||
LLXmlTreeNode* meta_node = archetype_node->getChildByName("meta");
|
||||
if (!meta_node)
|
||||
{
|
||||
llwarns << "No meta (2) in wearable import file: " << filename << llendl;
|
||||
}
|
||||
else if (!meta_node->getFastAttributeString(path_string, path))
|
||||
{
|
||||
llwarns << "meta tag in file: " << filename << " is missing the 'path' parameter." << llendl;
|
||||
}
|
||||
else if (!meta_node->getFastAttributeString(name_string, wearable_name))
|
||||
{
|
||||
llwarns << "meta tag in file: " << filename << " is missing the 'name' parameter." << llendl;
|
||||
}
|
||||
else if (!meta_node->getFastAttributeString(description_string, wearable_description))
|
||||
{
|
||||
llwarns << "meta tag in file: " << filename << " is missing the 'description' parameter." << llendl;
|
||||
}
|
||||
else
|
||||
{
|
||||
invalid = false;
|
||||
}
|
||||
if (invalid)
|
||||
{
|
||||
LLNotificationsUtil::add("AIXMLImportInvalidError", args);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the XML content.
|
||||
static LLStdStringHandle const id_string = LLXmlTree::addAttributeString("id");
|
||||
static LLStdStringHandle const value_string = LLXmlTree::addAttributeString("value");
|
||||
static LLStdStringHandle const te_string = LLXmlTree::addAttributeString("te");
|
||||
static LLStdStringHandle const uuid_string = LLXmlTree::addAttributeString("uuid");
|
||||
bool found_param = false;
|
||||
bool found_texture = false;
|
||||
for(LLXmlTreeNode* child = archetype_node->getFirstChild(); child; child = archetype_node->getNextChild())
|
||||
bool found_type = false;
|
||||
|
||||
bool different_grid = false; // By default assume it was exported on the same grid as we're on now.
|
||||
bool mixed_grids = false; // Set to true if two different grids (might) share UUIDs. Currently only "secondlife" and "secondlife_beta".
|
||||
std::string gridnick;
|
||||
std::string wearable_types;
|
||||
|
||||
try
|
||||
{
|
||||
if (child->hasName("param"))
|
||||
//-------------------------------------------------------------------------
|
||||
// <linden_genepool version="1.0" [metaversion="?"]> (root)
|
||||
//-------------------------------------------------------------------------
|
||||
std::string metaversion;
|
||||
U32 metaversion_major;
|
||||
|
||||
AIXMLParser linden_genepool(filename, "wearable import file", "linden_genepool", 1);
|
||||
linden_genepool.attribute("version", "1.0");
|
||||
linden_genepool.attribute("metaversion", metaversion);
|
||||
|
||||
if (!LLStringUtil::convertToU32(metaversion, metaversion_major) || metaversion_major > 1)
|
||||
{
|
||||
std::string id_s;
|
||||
U32 id;
|
||||
std::string value_s;
|
||||
F32 value;
|
||||
if (!child->getFastAttributeString(id_string, id_s) || !LLStringUtil::convertToU32(id_s, id) ||
|
||||
!child->getFastAttributeString(value_string, value_s) || !LLStringUtil::convertToF32(value_s, value))
|
||||
{
|
||||
llwarns << "Possible syntax error or corruption for <param id=... value=... /> node in " << filename << llendl;
|
||||
continue;
|
||||
}
|
||||
LLVisualParam* visual_param = edit_wearable->getVisualParam(id);
|
||||
if (visual_param)
|
||||
{
|
||||
found_param = true;
|
||||
visual_param->setWeight(value, FALSE);
|
||||
}
|
||||
THROW_MALERT("AIXMLImportRootVersionError", args("[TAG]", "metaversion")("[VERSIONMAJOR]", "1"));
|
||||
}
|
||||
else if (child->hasName("texture"))
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// <meta gridnick="secondlife" date="2013-07-20T15:27:55.80Z">
|
||||
//-------------------------------------------------------------------------
|
||||
AIXMLLindenGenepool::MetaData meta_data;
|
||||
|
||||
if (metaversion_major >= 1)
|
||||
{
|
||||
std::string te_s;
|
||||
S32 te;
|
||||
std::string uuid_s;
|
||||
LLUUID uuid;
|
||||
if (!child->getFastAttributeString(te_string, te_s) || !LLStringUtil::convertToS32(te_s, te) || te < 0 || te >= TEX_NUM_INDICES ||
|
||||
!child->getFastAttributeString(uuid_string, uuid_s) || !uuid.set(uuid_s, TRUE))
|
||||
linden_genepool.child("meta", meta_data);
|
||||
std::string current_gridnick = gHippoGridManager->getConnectedGrid()->getGridNick();
|
||||
gridnick = meta_data.mGridNick;
|
||||
different_grid = gridnick != current_gridnick;
|
||||
mixed_grids = (gridnick == "secondlife" && current_gridnick == "secondlife_beta") ||
|
||||
(gridnick == "secondlife_beta" && current_gridnick == "secondlife");
|
||||
}
|
||||
|
||||
std::vector<AIArchetype> archetypes;
|
||||
linden_genepool.setVersion(metaversion_major);
|
||||
linden_genepool.push_back_children("archetype", archetypes);
|
||||
|
||||
if (archetypes.empty())
|
||||
{
|
||||
THROW_ALERT("AIXMLImportNoArchetypeError", AIArgs("[FILE]", filename));
|
||||
}
|
||||
|
||||
for (std::vector<AIArchetype>::iterator archetype = archetypes.begin(); archetype != archetypes.end(); ++archetype)
|
||||
{
|
||||
LLWearableType::EType type = archetype->getType();
|
||||
if (type != LLWearableType::WT_NONE)
|
||||
{
|
||||
llwarns << "Possible syntax error or corruption for <texture te=... uuid=... /> node in " << filename << llendl;
|
||||
continue;
|
||||
}
|
||||
ETextureIndex te_index = (ETextureIndex)te;
|
||||
LLWearableType::EType te_wearable_type = LLAvatarAppearanceDictionary::getTEWearableType(te_index);
|
||||
if (te_wearable_type == edit_wearable->getType())
|
||||
{
|
||||
found_texture = true;
|
||||
if (!different_grid || mixed_grids)
|
||||
if (!wearable_types.empty())
|
||||
{
|
||||
panel_edit_wearable->setNewImageID(te_index, uuid);
|
||||
wearable_types += "/";
|
||||
}
|
||||
wearable_types += LLWearableType::getTypeName(type);
|
||||
if (panel_wearable_type == type)
|
||||
{
|
||||
found_type = true;
|
||||
}
|
||||
}
|
||||
for (AIArchetype::params_type::const_iterator param = archetype->getParams().begin(); param != archetype->getParams().end(); ++param)
|
||||
{
|
||||
LLVisualParam* visual_param = edit_wearable->getVisualParam(param->getID());
|
||||
if (visual_param)
|
||||
{
|
||||
found_param = true;
|
||||
visual_param->setWeight(param->getValue(), FALSE);
|
||||
}
|
||||
}
|
||||
for (AIArchetype::textures_type::const_iterator texture = archetype->getTextures().begin(); texture != archetype->getTextures().end(); ++texture)
|
||||
{
|
||||
U32 te = texture->getID();
|
||||
if (te >= TEX_NUM_INDICES)
|
||||
{
|
||||
}
|
||||
ETextureIndex te_index = (ETextureIndex)te;
|
||||
LLWearableType::EType te_wearable_type = LLAvatarAppearanceDictionary::getTEWearableType(te_index);
|
||||
if (te_wearable_type == edit_wearable->getType())
|
||||
{
|
||||
found_texture = true;
|
||||
if (!different_grid || mixed_grids)
|
||||
{
|
||||
panel_edit_wearable->setNewImageID(te_index, texture->getUUID());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (AIAlert::Error const& error)
|
||||
{
|
||||
AIAlert::add_modal("AIXMLImportError", AIArgs("[TYPE]", label), error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (found_param || found_texture)
|
||||
{
|
||||
edit_wearable->writeToAvatar(gAgentAvatarp);
|
||||
@@ -546,23 +444,25 @@ void LLFloaterCustomize::onBtnImport_continued(AIFilePicker* filepicker)
|
||||
panel_edit_wearable->updateScrollingPanelUI();
|
||||
if (found_texture && different_grid)
|
||||
{
|
||||
args["EXPORTGRID"] = gridnick;
|
||||
args["CURRENTGRID"] = gHippoGridManager->getConnectedGrid()->getGridNick();
|
||||
args("[EXPORTGRID]", gridnick);
|
||||
args("[CURRENTGRID]", gHippoGridManager->getConnectedGrid()->getGridNick());
|
||||
if (mixed_grids)
|
||||
{
|
||||
LLNotificationsUtil::add("AIXMLImportMixedGrid", args);
|
||||
AIAlert::add_modal("AIXMLImportMixedGrid", args);
|
||||
}
|
||||
else
|
||||
{
|
||||
LLNotificationsUtil::add("AIXMLImportDifferentGrid", args);
|
||||
AIAlert::add_modal("AIXMLImportDifferentGrid", args);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (found_type)
|
||||
{
|
||||
args["TYPE"] = panel_edit_wearable->LLPanel::getLabel();
|
||||
args["ARCHETYPENAME"] = label;
|
||||
LLNotificationsUtil::add("AIXMLImportWearableTypeMismatch", args);
|
||||
AIAlert::add("AIXMLImportEmptyArchetype", args("[TYPE]", label));
|
||||
}
|
||||
else if (!wearable_types.empty())
|
||||
{
|
||||
AIAlert::add("AIXMLImportWearableTypeMismatch", args("[TYPE]", label)("[ARCHETYPENAME]", wearable_types));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -615,21 +515,26 @@ void LLFloaterCustomize::onBtnExport_continued(LLViewerWearable* edit_wearable,
|
||||
}
|
||||
|
||||
std::string filename = filepicker->getFilename();
|
||||
LLSD args(LLSD::emptyMap());
|
||||
args["FILE"] = filename;
|
||||
|
||||
LLAPRFile outfile;
|
||||
outfile.open(filename, LL_APR_WB);
|
||||
if (!outfile.getFileHandle())
|
||||
bool success = false;
|
||||
try
|
||||
{
|
||||
llwarns << "Could not open \"" << filename << "\" for writing." << llendl;
|
||||
LLNotificationsUtil::add("AIXMLExportWriteError", args);
|
||||
return;
|
||||
AIFile outfile(filename, "wb");
|
||||
|
||||
AIXMLLindenGenepool linden_genepool(outfile);
|
||||
linden_genepool.child(edit_wearable->getArchetype());
|
||||
|
||||
success = true;
|
||||
}
|
||||
catch (AIAlert::Error const& error)
|
||||
{
|
||||
AIAlert::add_modal("AIXMLExportWriteError", AIArgs("[FILE]", filename), error);
|
||||
}
|
||||
|
||||
LLVOAvatar::dumpArchetypeXML_header(outfile, edit_wearable->getTypeName());
|
||||
edit_wearable->archetypeExport(outfile);
|
||||
LLVOAvatar::dumpArchetypeXML_footer(outfile);
|
||||
if (success)
|
||||
{
|
||||
AIAlert::add_modal("AIXMLExportSuccess", AIArgs("[FILE]", filename));
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterCustomize::onBtnOk()
|
||||
|
||||
@@ -297,6 +297,8 @@ LLViewerRegion::LLViewerRegion(const U64 &handle,
|
||||
mRegionFlags( REGION_FLAGS_DEFAULT ),
|
||||
mRegionProtocols( 0 ),
|
||||
mSimAccess( SIM_ACCESS_MIN ),
|
||||
mLastSimAccess( 0 ),
|
||||
mSimAccessString( "unknown" ),
|
||||
mBillableFactor(1.0),
|
||||
mMaxTasks(DEFAULT_MAX_REGION_WIDE_PRIM_COUNT),
|
||||
mCentralBakeVersion(0),
|
||||
@@ -599,9 +601,15 @@ BOOL LLViewerRegion::canManageEstate() const
|
||||
|| gAgent.getID() == getOwner();
|
||||
}
|
||||
|
||||
const std::string LLViewerRegion::getSimAccessString() const
|
||||
std::string const& LLViewerRegion::getSimAccessString()
|
||||
{
|
||||
return accessToString(mSimAccess);
|
||||
// Singu: added a cache because this is called every frame.
|
||||
if (mLastSimAccess != mSimAccess)
|
||||
{
|
||||
mSimAccessString = accessToString(mSimAccess);
|
||||
mLastSimAccess = mSimAccess;
|
||||
}
|
||||
return mSimAccessString;
|
||||
}
|
||||
|
||||
std::string LLViewerRegion::getLocalizedSimProductName() const
|
||||
@@ -2134,4 +2142,4 @@ U32 LLViewerRegion::getMaxMaterialsPerTransaction() const
|
||||
max_entries = mSimulatorFeatures[ "MaxMaterialsPerTransaction" ].asInteger();
|
||||
}
|
||||
return max_entries;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,8 +204,8 @@ public:
|
||||
|
||||
void setSimAccess(U8 sim_access) { mSimAccess = sim_access; }
|
||||
U8 getSimAccess() const { return mSimAccess; }
|
||||
const std::string getSimAccessString() const;
|
||||
|
||||
std::string const& getSimAccessString(); // Singu note: return reference to mSimAccessString.
|
||||
|
||||
// Homestead-related getters; there are no setters as nobody should be
|
||||
// setting them other than the individual message handler which is a member
|
||||
S32 getSimClassID() const { return mClassID; }
|
||||
@@ -430,6 +430,8 @@ private:
|
||||
U64 mRegionFlags; // includes damage flags
|
||||
U64 mRegionProtocols; // protocols supported by this region
|
||||
U8 mSimAccess;
|
||||
U8 mLastSimAccess; // Singularity extension.
|
||||
std::string mSimAccessString; // Singularity extension.
|
||||
F32 mBillableFactor;
|
||||
U32 mMaxTasks; // max prim count
|
||||
F32 mCameraDistanceSquared; // updated once per frame
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "llviewerregion.h"
|
||||
#include "llinventoryobserver.h"
|
||||
#include "llinventoryfunctions.h"
|
||||
#include "aixmllindengenepool.h"
|
||||
|
||||
using namespace LLAvatarAppearanceDefines;
|
||||
|
||||
@@ -134,32 +135,18 @@ LLWearable::EImportResult LLViewerWearable::importStream( std::istream& input_st
|
||||
return result;
|
||||
}
|
||||
|
||||
extern void dump_visual_param(LLAPRFile& file, LLVisualParam const* viewer_param, F32 value);
|
||||
|
||||
void LLViewerWearable::archetypeExport(LLAPRFile& file) const
|
||||
AIArchetype LLViewerWearable::getArchetype(void) const
|
||||
{
|
||||
apr_file_t* fp = file.getFileHandle();
|
||||
|
||||
std::string path;
|
||||
append_path_short(mItemID, path);
|
||||
apr_file_printf(fp, " <meta path=\"%s\" name=\"%s\" description=\"%s\"/>\n",
|
||||
LLXMLNode::escapeXML(path).c_str(),
|
||||
LLXMLNode::escapeXML(mName).c_str(),
|
||||
LLXMLNode::escapeXML(mDescription).c_str());
|
||||
|
||||
AIArchetype archetype(this);
|
||||
for (visual_param_index_map_t::const_iterator iter = mVisualParamIndexMap.begin(); iter != mVisualParamIndexMap.end(); ++iter)
|
||||
{
|
||||
LLVisualParam const* param = iter->second;
|
||||
dump_visual_param(file, param, param->getWeight());
|
||||
archetype.add(AIVisualParamIDValuePair(iter->second));
|
||||
}
|
||||
for (te_map_t::const_iterator iter = mTEMap.begin(); iter != mTEMap.end(); ++iter)
|
||||
{
|
||||
S32 te = iter->first;
|
||||
LLUUID const& image_id = iter->second->getID();
|
||||
apr_file_printf(fp, " <texture te=\"%i\" uuid=\"%s\"/>\n", te, image_id.asString().c_str());
|
||||
archetype.add(AITextureIDUUIDPair(iter->first, iter->second->getID()));
|
||||
}
|
||||
|
||||
apr_file_printf(fp, "\n");
|
||||
return archetype;
|
||||
}
|
||||
|
||||
// Avatar parameter and texture definitions can change over time.
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#include "llwearable.h"
|
||||
#include "llavatarappearancedefines.h"
|
||||
#include "aixmllindengenepool.h"
|
||||
|
||||
class LLVOAvatar;
|
||||
class LLAPRFile;
|
||||
@@ -67,8 +68,9 @@ public:
|
||||
|
||||
/*virtual*/ EImportResult importStream( std::istream& input_stream, LLAvatarAppearance* avatarp );
|
||||
|
||||
void archetypeExport(LLAPRFile& file) const;
|
||||
|
||||
// Singu extension.
|
||||
AIArchetype getArchetype(void) const;
|
||||
|
||||
void setParamsToDefaults();
|
||||
void setTexturesToDefaults();
|
||||
|
||||
|
||||
@@ -112,6 +112,8 @@
|
||||
|
||||
#include "llfloaterexploreanimations.h"
|
||||
#include "aihttptimeoutpolicy.h"
|
||||
#include "aixmllindengenepool.h"
|
||||
#include "aifile.h"
|
||||
|
||||
#include "llavatarname.h"
|
||||
|
||||
@@ -7672,29 +7674,10 @@ bool LLVOAvatar::visualParamWeightsAreDefault()
|
||||
|
||||
void dump_visual_param(LLAPRFile& file, LLVisualParam const* viewer_param, F32 value)
|
||||
{
|
||||
std::string type_string = "unknown";
|
||||
if (dynamic_cast<LLTexLayerParamAlpha const*>(viewer_param))
|
||||
type_string = "param_alpha";
|
||||
if (dynamic_cast<LLTexLayerParamColor const*>(viewer_param))
|
||||
type_string = "param_color";
|
||||
if (dynamic_cast<LLDriverParam const*>(viewer_param))
|
||||
type_string = "param_driver";
|
||||
if (dynamic_cast<LLPolyMorphTarget const*>(viewer_param))
|
||||
type_string = "param_morph";
|
||||
if (dynamic_cast<LLPolySkeletalDistortion const*>(viewer_param))
|
||||
type_string = "param_skeleton";
|
||||
S32 wtype = -1;
|
||||
LLViewerVisualParam const* vparam = dynamic_cast<LLViewerVisualParam const*>(viewer_param);
|
||||
if (vparam)
|
||||
{
|
||||
wtype = vparam->getWearableType();
|
||||
}
|
||||
S32 u8_value = F32_to_U8(value,viewer_param->getMinWeight(),viewer_param->getMaxWeight());
|
||||
apr_file_printf(file.getFileHandle(), " <param id=\"%d\" name=\"%s\" value=\"%.3f\" u8=\"%d\" type=\"%s\" wearable=\"%s\"/>\n",
|
||||
viewer_param->getID(), viewer_param->getName().c_str(), value, u8_value, type_string.c_str(),
|
||||
LLWearableType::getTypeName(LLWearableType::EType(wtype)).c_str()
|
||||
// param_location_name(vparam->getParamLocation()).c_str()
|
||||
);
|
||||
viewer_param->getID(), viewer_param->getName().c_str(), value, u8_value, viewer_param->getTypeString(),
|
||||
viewer_param->getDumpWearableTypeName().c_str());
|
||||
}
|
||||
|
||||
void LLVOAvatar::dumpAppearanceMsgParams( const std::string& dump_prefix,
|
||||
@@ -8352,127 +8335,83 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara
|
||||
dumpArchetypeXML_cont(fullpath, group_by_wearables);
|
||||
}
|
||||
|
||||
// metaversion 1.0
|
||||
// ===============
|
||||
//
|
||||
// Added as child of <linden_genepool>:
|
||||
//
|
||||
// <meta gridnick="secondlife" date="2013-07-16T16:49:00.40Z"/>
|
||||
//
|
||||
// Optionally, as child of <archetype>, the following node may appear:
|
||||
//
|
||||
// <meta path="clothing/jackets" name="Purple jacket" description="A jacket with mainly the color purple">
|
||||
//
|
||||
// Furthermore, metaversion 1.0 and higher allow the occurance of one or more <archetype> blocks.
|
||||
// If this is used then it is strongly advised to use one <archetype> per wearable, so that
|
||||
// the the <meta> node makes sense (it then refers to the wearable of that <archetype>).
|
||||
//
|
||||
// The reason for this clumsy way to link wearable to extra meta data is to stay
|
||||
// compatible with the older format (no metaversion).
|
||||
//
|
||||
//static
|
||||
void LLVOAvatar::dumpArchetypeXML_header(LLAPRFile& file, std::string const& archetype_name)
|
||||
{
|
||||
apr_file_t* fp = file.getFileHandle();
|
||||
apr_file_printf(fp, "<?xml version=\"1.0\" encoding=\"US-ASCII\" standalone=\"yes\"?>\n");
|
||||
apr_file_printf(fp, "<linden_genepool version=\"1.0\" metaversion=\"1.0\">\n");
|
||||
apr_file_printf(fp, " <meta gridnick=\"%s\" date=\"%s\"/>\n",
|
||||
LLXMLNode::escapeXML(gHippoGridManager->getConnectedGrid()->getGridNick()).c_str(),
|
||||
LLDate::now().asString().c_str());
|
||||
apr_file_printf(fp, " <archetype name=\"%s\">\n", archetype_name.c_str());
|
||||
}
|
||||
|
||||
//static
|
||||
void LLVOAvatar::dumpArchetypeXML_footer(LLAPRFile& file)
|
||||
{
|
||||
apr_file_t* fp = file.getFileHandle();
|
||||
apr_file_printf(fp, " </archetype>\n");
|
||||
apr_file_printf(fp, "</linden_genepool>\n");
|
||||
}
|
||||
|
||||
void LLVOAvatar::dumpArchetypeXML_cont(std::string const& fullpath, bool group_by_wearables)
|
||||
{
|
||||
LLAPRFile outfile;
|
||||
outfile.open(fullpath, LL_APR_WB );
|
||||
apr_file_t* file = outfile.getFileHandle();
|
||||
if (!file)
|
||||
try
|
||||
{
|
||||
return;
|
||||
AIFile outfile(fullpath, "wb");
|
||||
AIXMLLindenGenepool linden_genepool(outfile);
|
||||
|
||||
if (group_by_wearables)
|
||||
{
|
||||
for (S32 type = LLWearableType::WT_SHAPE; type < LLWearableType::WT_COUNT; type++)
|
||||
{
|
||||
AIArchetype archetype((LLWearableType::EType)type);
|
||||
|
||||
for (LLVisualParam* param = getFirstVisualParam(); param; param = getNextVisualParam())
|
||||
{
|
||||
LLViewerVisualParam* viewer_param = (LLViewerVisualParam*)param;
|
||||
if( (viewer_param->getWearableType() == type) &&
|
||||
(viewer_param->isTweakable() ) )
|
||||
{
|
||||
archetype.add(AIVisualParamIDValuePair(param));
|
||||
}
|
||||
}
|
||||
|
||||
for (U8 te = 0; te < TEX_NUM_INDICES; te++)
|
||||
{
|
||||
if (LLAvatarAppearanceDictionary::getTEWearableType((ETextureIndex)te) == type)
|
||||
{
|
||||
// MULTIPLE_WEARABLES: extend to multiple wearables?
|
||||
LLViewerTexture* te_image = getImage((ETextureIndex)te, 0);
|
||||
if( te_image )
|
||||
{
|
||||
archetype.add(AITextureIDUUIDPair(te, te_image->getID()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
linden_genepool.child(archetype);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Just dump all params sequentially.
|
||||
AIArchetype archetype; // Legacy: Type is set to WT_NONE and will result in <archetype name="???">.
|
||||
|
||||
for (LLVisualParam* param = getFirstVisualParam(); param; param = getNextVisualParam())
|
||||
{
|
||||
archetype.add(AIVisualParamIDValuePair(param));
|
||||
}
|
||||
|
||||
for (U8 te = 0; te < TEX_NUM_INDICES; te++)
|
||||
{
|
||||
{
|
||||
// MULTIPLE_WEARABLES: extend to multiple wearables?
|
||||
LLViewerTexture* te_image = getImage((ETextureIndex)te, 0);
|
||||
if( te_image )
|
||||
{
|
||||
archetype.add(AITextureIDUUIDPair(te, te_image->getID()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
linden_genepool.child(archetype);
|
||||
}
|
||||
|
||||
#if 0 // Wasn't used anyway.
|
||||
bool ultra_verbose = false;
|
||||
if (isSelf() && ultra_verbose)
|
||||
{
|
||||
// show the cloned params inside the wearables as well.
|
||||
gAgentAvatarp->dumpWearableInfo(outfile);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
catch (AIAlert::Error const& error)
|
||||
{
|
||||
llinfos << "xmlfile write handle obtained : " << fullpath << llendl;
|
||||
AIAlert::add_modal("AIXMLdumpArchetypeXMLError", AIArgs("[FILE]", fullpath), error);
|
||||
}
|
||||
|
||||
LLVOAvatar::dumpArchetypeXML_header(outfile);
|
||||
|
||||
if (group_by_wearables)
|
||||
{
|
||||
for (S32 type = LLWearableType::WT_SHAPE; type < LLWearableType::WT_COUNT; type++)
|
||||
{
|
||||
const std::string& wearable_name = LLWearableType::getTypeName((LLWearableType::EType)type);
|
||||
apr_file_printf( file, "\n\t\t<!-- wearable: %s -->\n", wearable_name.c_str() );
|
||||
|
||||
for (LLVisualParam* param = getFirstVisualParam(); param; param = getNextVisualParam())
|
||||
{
|
||||
LLViewerVisualParam* viewer_param = (LLViewerVisualParam*)param;
|
||||
if( (viewer_param->getWearableType() == type) &&
|
||||
(viewer_param->isTweakable() ) )
|
||||
{
|
||||
dump_visual_param(outfile, viewer_param, viewer_param->getWeight());
|
||||
}
|
||||
}
|
||||
|
||||
for (U8 te = 0; te < TEX_NUM_INDICES; te++)
|
||||
{
|
||||
if (LLAvatarAppearanceDictionary::getTEWearableType((ETextureIndex)te) == type)
|
||||
{
|
||||
// MULTIPLE_WEARABLES: extend to multiple wearables?
|
||||
LLViewerTexture* te_image = getImage((ETextureIndex)te, 0);
|
||||
if( te_image )
|
||||
{
|
||||
std::string uuid_str;
|
||||
te_image->getID().toString( uuid_str );
|
||||
apr_file_printf( file, "\t\t<texture te=\"%i\" uuid=\"%s\"/>\n", te, uuid_str.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Just dump all params sequentially.
|
||||
for (LLVisualParam* param = getFirstVisualParam(); param; param = getNextVisualParam())
|
||||
{
|
||||
LLViewerVisualParam* viewer_param = (LLViewerVisualParam*)param;
|
||||
dump_visual_param(outfile, viewer_param, viewer_param->getWeight());
|
||||
}
|
||||
|
||||
for (U8 te = 0; te < TEX_NUM_INDICES; te++)
|
||||
{
|
||||
{
|
||||
// MULTIPLE_WEARABLES: extend to multiple wearables?
|
||||
LLViewerTexture* te_image = getImage((ETextureIndex)te, 0);
|
||||
if( te_image )
|
||||
{
|
||||
std::string uuid_str;
|
||||
te_image->getID().toString( uuid_str );
|
||||
apr_file_printf( file, "\t\t<texture te=\"%i\" uuid=\"%s\"/>\n", te, uuid_str.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
LLVOAvatar::dumpArchetypeXML_footer(outfile);
|
||||
|
||||
bool ultra_verbose = false;
|
||||
if (isSelf() && ultra_verbose)
|
||||
{
|
||||
// show the cloned params inside the wearables as well.
|
||||
gAgentAvatarp->dumpWearableInfo(outfile);
|
||||
}
|
||||
// File will close when handle goes out of scope
|
||||
}
|
||||
|
||||
void LLVOAvatar::setVisibilityRank(U32 rank)
|
||||
|
||||
@@ -69,25 +69,6 @@
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<notification name="AIXMLExportWriteError">Export Failure: could not open file "[FILE]" for writing.</notification>
|
||||
|
||||
<notification name="AIXMLImportGridMismatch">Import Warning: could not apply textures: [FILE] was exported on grid "[GRIDNAME]" while the currentgrid is "[CURGRID]".</notification>
|
||||
|
||||
<notification name="AIXMLImportParseError">Import Failure: could not read or parse wearable import file "[FILE]".</notification>
|
||||
|
||||
<notification name="AIXMLImportRootTypeError">Import Failure: the file "[FILE]" is not a linden_genepool XML file.</notification>
|
||||
|
||||
<notification name="AIXMLImportRootVersionError">Import Failure: the file "[FILE]" contains linden_genepool XML data with the wrong [TAG]. Version "[VERSIONMAJOR].0" or less is required.</notification>
|
||||
|
||||
<notification name="AIXMLImportInvalidError">Import Failure: the file "[FILE]" contains invalid data.</notification>
|
||||
|
||||
<notification name="AIXMLImportDifferentGrid">Import was successful but note that the wearable was exported on grid [EXPORTGRID] (and the current grid is [CURRENTGRID]). Texture UUIDs have NOT been applied!</notification>
|
||||
|
||||
<notification name="AIXMLImportMixedGrid">Import was successful but note that the wearable was exported on grid [EXPORTGRID] (and the current grid is [CURRENTGRID]). Texture UUIDs have been applied but might not exist here!</notification>
|
||||
|
||||
<notification name="AIXMLImportWearableTypeMismatch">Import Warning: the file "[FILE]" does not contain a wearable of type [TYPE].
|
||||
It contains an archetype of type [ARCHETYPENAME]. Please select the correct type before importing.</notification>
|
||||
|
||||
<notification name="MediaAlert">Der Besitzer der Parzelle möchte Ihren Viewer anweisen die folgende [TYPE] URL zu laden:[URL]Sie können die korrespondierende Domäne oder In-Welt Objekt-Skript-Server erlauben oder ablehnen."Erlauben" und "Verweigern" gelten nur für die aktuelle Sitzung, während "Immer sperren" bzw. "Immer erlauben" dann immer gelten.<form name="form">
|
||||
<button name="Allow" text="erlauben"/>
|
||||
<button name="Deny" text="verbieten"/>
|
||||
|
||||
@@ -133,68 +133,18 @@
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="AIXMLExportWriteError"
|
||||
type="alertmodal">
|
||||
Export Failure: could not open file "[FILE]" for writing.
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="alert.tga"
|
||||
name="AIXMLImportGridMismatch"
|
||||
name="AIAlert"
|
||||
type="alert">
|
||||
Import Warning: could not apply textures: [FILE] was exported on grid "[GRIDNAME]" while the currentgrid is "[CURGRID]".
|
||||
[PAYLOAD]
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="AIXMLImportParseError"
|
||||
name="AIAlertModal"
|
||||
type="alertmodal">
|
||||
Import Failure: could not read or parse wearable import file "[FILE]".
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="AIXMLImportRootTypeError"
|
||||
type="alertmodal">
|
||||
Import Failure: the file "[FILE]" is not a linden_genepool XML file.
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="AIXMLImportRootVersionError"
|
||||
type="alertmodal">
|
||||
Import Failure: the file "[FILE]" contains linden_genepool XML data with the wrong [TAG]. Version "[VERSIONMAJOR].0" or less is required.
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="AIXMLImportInvalidError"
|
||||
type="alertmodal">
|
||||
Import Failure: the file "[FILE]" contains invalid data.
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="AIXMLImportDifferentGrid"
|
||||
type="alertmodal">
|
||||
Import was successful but note that the wearable was exported on grid [EXPORTGRID] (and the current grid is [CURRENTGRID]). Texture UUIDs have NOT been applied!
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="AIXMLImportMixedGrid"
|
||||
type="alertmodal">
|
||||
Import was successful but note that the wearable was exported on grid [EXPORTGRID] (and the current grid is [CURRENTGRID]). Texture UUIDs have been applied but might not exist here!
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
icon="alert.tga"
|
||||
name="AIXMLImportWearableTypeMismatch"
|
||||
type="alert">
|
||||
Import Warning: the file "[FILE]" does not contain a wearable of type [TYPE].
|
||||
It contains an archetype of type [ARCHETYPENAME]. Please select the correct type before importing.
|
||||
[PAYLOAD]
|
||||
</notification>
|
||||
|
||||
<notification
|
||||
|
||||
@@ -4367,4 +4367,55 @@ Try enclosing path to the editor with double quotes.
|
||||
<!-- teleport_strings.xml's strings we need -->
|
||||
<string name="completed_from">Teleport completed from</string>
|
||||
|
||||
<!-- AIAlert messages -->
|
||||
<string name="AIPrefix">"[PREFIX]: "</string>
|
||||
|
||||
<!-- AIFile exception alerts -->
|
||||
<string name="AIFile_mkdir_Failed_to_create_DIRNAME">Failed to create folder [DIRNAME]: [ERROR]</string>
|
||||
<string name="AIFile_rmdir_Failed_to_remove_DIRNAME">Failed to remove folder [DIRNAME]: [ERROR]</string>
|
||||
<string name="AIFile_fopen_Failed_to_open_FILENAME">Failed to open file "[FILENAME]": [ERROR]</string>
|
||||
<string name="AIFile_close_Failed_to_close_file">Failed to close file: [ERROR]</string>
|
||||
<string name="AIFile_remove_Failed_to_remove_FILENAME">Failed to remove file [FILENAME]: [ERROR]</string>
|
||||
<string name="AIFile_rename_Failed_to_rename_FILE_to_NEWFILE">Failed to rename file [FILE] to [NEWFILE]: [ERROR]</string>
|
||||
|
||||
<!-- AIXMLElement exception alerts -->
|
||||
<string name="AIXMLElement_attribute_Failed_to_write_DATA">Failed to write '[DATA]', writing attribute data.</string>
|
||||
<string name="AIXMLElement_child_Bad_ostream">ostream not good after calling child.toXML</string>
|
||||
<string name="AIXMLElement_write_child_Failed_to_write_DATA">Failed to write '[DATA]', writing child data.</string>
|
||||
<string name="AIXMLElement_Failed_to_write_DATA">Failed to write '[DATA]', opening new child.</string>
|
||||
<string name="AIXMLElement_closing_child_Failed_to_write_DATA">Failed to write '[DATA]', closing previous child.</string>
|
||||
|
||||
<!-- AIXMLStream exception alerts -->
|
||||
<string name="AIXMLStream_fprintf_failed_to_write_xml_header">Failed to write XML header.</string>
|
||||
|
||||
<!-- AIXMLParser exception alerts -->
|
||||
<string name="AIXMLParser_Cannot_parse_FILEDESC_FILENAME">Cannot parse [FILEDESC] "[FILENAME]".</string>
|
||||
<string name="AIXMLParser_No_root_node_found_in_FILEDESC_FILENAME">No root node found in [FILEDESC] "[FILENAME]".</string>
|
||||
<string name="AIXMLParser_Missing_header_NAME_invalid_FILEDESC_FILENAME">Missing header '[NAME]' ; invalid [FILEDESC] "[FILENAME]".</string>
|
||||
<string name="AIXMLParser_Invalid_or_missing_NAME_version_attribute_in_FILEDESC_FILENAME">Invalid or missing [NAME] 'version' attribute in [FILEDESC] "[FILENAME]".</string>
|
||||
<string name="AIXMLParser_Incompatible_NAME_version_MAJOR_MINOR_in">Incompatible '[NAME]' version, [MAJOR].[MINOR], in [FILEDESC] "[FILENAME]".</string>
|
||||
|
||||
<!-- AIXMLElementParser exception alerts -->
|
||||
<string name="AIXMLElementParser_read_string_Invalid_MD5_VALUE_in_FILEDESC_FILENAME">Invalid MD5 ([VALUE]) in [FILEDESC] "[FILENAME]".</string>
|
||||
<string name="AIXMLElementParser_read_string_Invalid_boolean_VALUE_in_FILEDESC_FILENAME">Invalid boolean ([VALUE]) in [FILEDESC] "[FILENAME]".</string>
|
||||
<string name="AIXMLElementParser_attribute_Missing_NAME_attribute_in_NODENAME_of_FILEDESC_FILENAME">Missing '[NAME]' attribute in [NODENAME] of [FILEDESC] "[FILENAME]".</string>"
|
||||
<string name="AIXMLElementParser_attribute_Invalid_NAME_attribute_should_be_REQUIRED_in_NODENAME_of_FILEDESC_FILENAME">Invalid '[NAME]' attribute (should be '[REQUIRED]') in [NODENAME] of [FILEDESC] "[FILENAME]".</string>
|
||||
<string name="AIXMLElementParser_read_child_Invalid_uuid_in_FILEDESC_FILENAME">Invalid UUID in [FILEDESC] "[FILENAME]".</string>
|
||||
<string name="AIXMLElementParser_read_child_Invalid_date_DATE_in_FILEDESC_FILENAME">Invalid DATE ([DATE]) in [FILEDESC] "[FILENAME]".</string>
|
||||
|
||||
<!-- AIArchetype exception alerts -->
|
||||
<string name="AIArchetype_archetype_has_no_meta">archetype has no <meta> element.</string>
|
||||
<string name="AIArchetype_MetaData_archetype_meta_has_no_ATTRIBUTE">archetype <meta> element has no '[ATTRIBUTE]' attribute.</string>
|
||||
|
||||
<string name="AIXMLdumpArchetypeXMLError">Failure dumping archetype to "[FILE]":</string>
|
||||
<string name="AIXMLExportSuccess">Successfully exported wearable to "[FILE]".</string>
|
||||
<string name="AIXMLExportWriteError">The export to file "[FILE]" failed:</string>
|
||||
<string name="AIXMLImportRootVersionError">Import Failure: the file "[FILE]" contains linden_genepool XML data with the wrong [TAG]. Version "[VERSIONMAJOR].0" or less is required.</string>
|
||||
<string name="AIXMLImportDifferentGrid">Import was successful but note that the wearable was exported on grid [EXPORTGRID] (and the current grid is [CURRENTGRID]). Texture UUIDs have NOT been applied!</string>
|
||||
<string name="AIXMLImportMixedGrid">Import was successful but note that the wearable was exported on grid [EXPORTGRID] (and the current grid is [CURRENTGRID]). Texture UUIDs have been applied but might not exist here!</string>
|
||||
<string name="AIXMLImportEmptyArchetype">Import warning: the file "[FILE]" contains a wearable of the selected type ([TYPE]), but contains no parameters or textures for that type. Nothing was imported.</string>
|
||||
<string name="AIXMLImportWearableTypeMismatch">Import warning: the file "[FILE]" does not contain a wearable of type [TYPE]. It contains an archetype of type [ARCHETYPENAME]. Please select the correct type before importing.</string>
|
||||
<string name="AIXMLImportError">Failed to import the [TYPE] wearable:</string>
|
||||
<string name="AIXMLImportNoArchetypeError">No archetype found in wearable import file "[FILE]".</string>
|
||||
|
||||
</strings>
|
||||
|
||||
@@ -73,44 +73,7 @@
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<notification name="AIXMLExportWriteError">
|
||||
Fallo de Exportación: no se puede abrir el archivo "[FILE]" para escritura.
|
||||
</notification>
|
||||
|
||||
<notification name="AIXMLImportGridMismatch">
|
||||
Aviso de Importación: No se pueden aplicar las texturas: El [FILE] fue exportado en el grid "[GRIDNAME]" mientras que el grid actual es "[CURGRID]".
|
||||
</notification>
|
||||
|
||||
<notification name="AIXMLImportParseError">
|
||||
Fallo de Importación: no se puede leer o analizar el archivo de vestimenta para importar "[FILE]".
|
||||
</notification>
|
||||
|
||||
<notification name="AIXMLImportRootTypeError">
|
||||
Fallo de Importación: el archivo "[FILE]" no es un archivo linden_genepool XML.
|
||||
</notification>
|
||||
|
||||
<notification name="AIXMLImportRootVersionError">
|
||||
Fallo de Importación: el archivo "[FILE]" contiene datos linden_genepool XML con [TAG] erróneo. Se requiere Versión "[VERSIONMAJOR].0" o inferior.
|
||||
</notification>
|
||||
|
||||
<notification name="AIXMLImportInvalidError">
|
||||
Fallo de Importación: el archivo "[FILE]" contiene datos inválidos.
|
||||
</notification>
|
||||
|
||||
<notification name="AIXMLImportDifferentGrid">
|
||||
La importación se ha realizado con exito, pero ten presente que el objeto vestible fue exportado desde el grid [EXPORTGRID] (y el grid actual es [CURRENTGRID]). ¡No se aplicaron las UUIDs de las Texturas!
|
||||
</notification>
|
||||
|
||||
<notification name="AIXMLImportMixedGrid">
|
||||
La importación se ha realizado con exito, pero ten presente que el objeto vestible fue exportado desde el grid [EXPORTGRID] (y el grid actual es [CURRENTGRID]).¡Se aplicaron las UUIDs de la Texturas pero quizás no existan aquí!
|
||||
</notification>
|
||||
|
||||
<notification name="AIXMLImportWearableTypeMismatch">
|
||||
Aviso de Importación: el archivo "[FILE]" no contiene un objeto vestible de tipo [TYPE].
|
||||
Éste contiene un arquetipo de tipo [ARCHETYPENAME]. Por favor, selecciona el tipo correcto antes de comenzar la importación.
|
||||
</notification>
|
||||
|
||||
|
||||
<notification name="MediaAlert">
|
||||
El propietario de esta parcela ha solicitado que el siguiente URL de [TYPE] sea cargado en tu visor:
|
||||
|
||||
|
||||
@@ -4836,5 +4836,58 @@ Intenta entrecomillando el camino al editor.
|
||||
|
||||
<!-- teleport_strings.xml's strings we need -->
|
||||
<string name="completed_from">Teleporte completado desde</string>
|
||||
|
||||
|
||||
<!-- ************ EVERYTHING BELOW STILL NEEDS TRANSLATION! ************** -->
|
||||
|
||||
<!-- AIAlert messages -->
|
||||
<string name="AIPrefix">"[PREFIX]: "</string>
|
||||
|
||||
<!-- AIFile exception alerts -->
|
||||
<string name="AIFile_mkdir_Failed_to_create_DIRNAME">Failed to create folder [DIRNAME]: [ERROR]</string>
|
||||
<string name="AIFile_rmdir_Failed_to_remove_DIRNAME">Failed to remove folder [DIRNAME]: [ERROR]</string>
|
||||
<string name="AIFile_fopen_Failed_to_open_FILENAME">Failed to open file "[FILENAME]": [ERROR]</string>
|
||||
<string name="AIFile_close_Failed_to_close_file">Failed to close file: [ERROR]</string>
|
||||
<string name="AIFile_remove_Failed_to_remove_FILENAME">Failed to remove file [FILENAME]: [ERROR]</string>
|
||||
<string name="AIFile_rename_Failed_to_rename_FILE_to_NEWFILE">Failed to rename file [FILE] to [NEWFILE]: [ERROR]</string>
|
||||
|
||||
<!-- AIXMLElement exception alerts -->
|
||||
<string name="AIXMLElement_attribute_Failed_to_write_DATA">Failed to write '[DATA]', writing attribute data.</string>
|
||||
<string name="AIXMLElement_child_Bad_ostream">ostream not good after calling child.toXML</string>
|
||||
<string name="AIXMLElement_write_child_Failed_to_write_DATA">Failed to write '[DATA]', writing child data.</string>
|
||||
<string name="AIXMLElement_Failed_to_write_DATA">Failed to write '[DATA]', opening new child.</string>
|
||||
<string name="AIXMLElement_closing_child_Failed_to_write_DATA">Failed to write '[DATA]', closing previous child.</string>
|
||||
|
||||
<!-- AIXMLStream exception alerts -->
|
||||
<string name="AIXMLStream_fprintf_failed_to_write_xml_header">Failed to write XML header.</string>
|
||||
|
||||
<!-- AIXMLParser exception alerts -->
|
||||
<string name="AIXMLParser_Cannot_parse_FILEDESC_FILENAME">Cannot parse [FILEDESC] "[FILENAME]".</string>
|
||||
<string name="AIXMLParser_No_root_node_found_in_FILEDESC_FILENAME">No root node found in [FILEDESC] "[FILENAME]".</string>
|
||||
<string name="AIXMLParser_Missing_header_NAME_invalid_FILEDESC_FILENAME">Missing header '[NAME]' ; invalid [FILEDESC] "[FILENAME]".</string>
|
||||
<string name="AIXMLParser_Invalid_or_missing_NAME_version_attribute_in_FILEDESC_FILENAME">Invalid or missing [NAME] 'version' attribute in [FILEDESC] "[FILENAME]".</string>
|
||||
<string name="AIXMLParser_Incompatible_NAME_version_MAJOR_MINOR_in">Incompatible '[NAME]' version, [MAJOR].[MINOR], in [FILEDESC] "[FILENAME]".</string>
|
||||
|
||||
<!-- AIXMLElementParser exception alerts -->
|
||||
<string name="AIXMLElementParser_read_string_Invalid_MD5_VALUE_in_FILEDESC_FILENAME">Invalid MD5 ([VALUE]) in [FILEDESC] "[FILENAME]".</string>
|
||||
<string name="AIXMLElementParser_read_string_Invalid_boolean_VALUE_in_FILEDESC_FILENAME">Invalid boolean ([VALUE]) in [FILEDESC] "[FILENAME]".</string>
|
||||
<string name="AIXMLElementParser_attribute_Missing_NAME_attribute_in_NODENAME_of_FILEDESC_FILENAME">Missing '[NAME]' attribute in [NODENAME] of [FILEDESC] "[FILENAME]".</string>"
|
||||
<string name="AIXMLElementParser_attribute_Invalid_NAME_attribute_should_be_REQUIRED_in_NODENAME_of_FILEDESC_FILENAME">Invalid '[NAME]' attribute (should be '[REQUIRED]') in [NODENAME] of [FILEDESC] "[FILENAME]".</string>
|
||||
<string name="AIXMLElementParser_read_child_Invalid_uuid_in_FILEDESC_FILENAME">Invalid UUID in [FILEDESC] "[FILENAME]".</string>
|
||||
<string name="AIXMLElementParser_read_child_Invalid_date_DATE_in_FILEDESC_FILENAME">Invalid DATE ([DATE]) in [FILEDESC] "[FILENAME]".</string>
|
||||
|
||||
<!-- AIArchetype exception alerts -->
|
||||
<string name="AIArchetype_archetype_has_no_meta">archetype has no <meta> element.</string>
|
||||
<string name="AIArchetype_MetaData_archetype_meta_has_no_ATTRIBUTE">archetype <meta> element has no '[ATTRIBUTE]' attribute.</string>
|
||||
|
||||
<string name="AIXMLdumpArchetypeXMLError">Failure dumping archetype to "[FILE]":</string>
|
||||
<string name="AIXMLExportSuccess">Successfully exported wearable to "[FILE]".</string>
|
||||
<string name="AIXMLExportWriteError">The export to file "[FILE]" failed:</string>
|
||||
<string name="AIXMLImportRootVersionError">Fallo de Importación: el archivo "[FILE]" contiene datos linden_genepool XML con [TAG] erróneo. Se requiere Versión "[VERSIONMAJOR].0" o inferior.</string>
|
||||
<string name="AIXMLImportDifferentGrid">La importación se ha realizado con exito, pero ten presente que el objeto vestible fue exportado desde el grid [EXPORTGRID] (y el grid actual es [CURRENTGRID]). ¡No se aplicaron las UUIDs de las Texturas!</string>
|
||||
<string name="AIXMLImportMixedGrid">La importación se ha realizado con exito, pero ten presente que el objeto vestible fue exportado desde el grid [EXPORTGRID] (y el grid actual es [CURRENTGRID]).¡Se aplicaron las UUIDs de la Texturas pero quizás no existan aquí!</string>
|
||||
<string name="AIXMLImportEmptyArchetype">Import warning: the file "[FILE]" contains a wearable of the selected type ([TYPE]), but contains no parameters or textures for that type. Nothing was imported.</string>
|
||||
<string name="AIXMLImportWearableTypeMismatch">Aviso de Importación: el archivo "[FILE]" no contiene un objeto vestible de tipo [TYPE]. Éste contiene un arquetipo de tipo [ARCHETYPENAME]. Por favor, selecciona el tipo correcto antes de comenzar la importación.</string>
|
||||
<string name="AIXMLImportError">Failed to import the [TYPE] wearable:</string>
|
||||
<string name="AIXMLImportNoArchetypeError">No archetype found in wearable import file "[FILE]".</string>
|
||||
|
||||
</strings>
|
||||
|
||||
Reference in New Issue
Block a user