diff --git a/indra/llappearance/lldriverparam.h b/indra/llappearance/lldriverparam.h
index 65dd3cdde..47d14d2a1 100644
--- a/indra/llappearance/lldriverparam.h
+++ b/indra/llappearance/lldriverparam.h
@@ -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();
diff --git a/indra/llappearance/llpolymorph.h b/indra/llappearance/llpolymorph.h
index 03915d3da..f1ecef881 100644
--- a/indra/llappearance/llpolymorph.h
+++ b/indra/llappearance/llpolymorph.h
@@ -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();
diff --git a/indra/llappearance/llpolyskeletaldistortion.h b/indra/llappearance/llpolyskeletaldistortion.h
index 774bc7dfa..a9b843af6 100644
--- a/indra/llappearance/llpolyskeletaldistortion.h
+++ b/indra/llappearance/llpolyskeletaldistortion.h
@@ -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; }
diff --git a/indra/llappearance/lltexlayerparams.h b/indra/llappearance/lltexlayerparams.h
index b38d28d3e..64a465a59 100644
--- a/indra/llappearance/lltexlayerparams.h
+++ b/indra/llappearance/lltexlayerparams.h
@@ -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; }
diff --git a/indra/llappearance/llviewervisualparam.cpp b/indra/llappearance/llviewervisualparam.cpp
index dd5331207..4a4f69c56 100644
--- a/indra/llappearance/llviewervisualparam.cpp
+++ b/indra/llappearance/llviewervisualparam.cpp
@@ -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,
diff --git a/indra/llappearance/llviewervisualparam.h b/indra/llappearance/llviewervisualparam.h
index 64364c881..39d29fccb 100644
--- a/indra/llappearance/llviewervisualparam.h
+++ b/indra/llappearance/llviewervisualparam.h
@@ -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;
diff --git a/indra/llappearance/llwearable.h b/indra/llappearance/llwearable.h
index b6049eb21..a944a16fd 100644
--- a/indra/llappearance/llwearable.h
+++ b/indra/llappearance/llwearable.h
@@ -41,6 +41,7 @@ class LLVisualParam;
class LLTexGlobalColorInfo;
class LLTexGlobalColor;
class LLAvatarAppearance;
+class AIArchetype;
// Abstract class.
class LLWearable
diff --git a/indra/llcharacter/llvisualparam.h b/indra/llcharacter/llvisualparam.h
index a5864c15c..6cb1fcaa6 100644
--- a/indra/llcharacter/llvisualparam.h
+++ b/indra/llcharacter/llvisualparam.h
@@ -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
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 2b4c37be0..be045f100 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -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
diff --git a/indra/llcommon/aialert.cpp b/indra/llcommon/aialert.cpp
new file mode 100644
index 000000000..f3d4f5af3
--- /dev/null
+++ b/indra/llcommon/aialert.cpp
@@ -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 .
+ *
+ * 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
+
diff --git a/indra/llcommon/aialert.h b/indra/llcommon/aialert.h
new file mode 100644
index 000000000..83a0da300
--- /dev/null
+++ b/indra/llcommon/aialert.h
@@ -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 .
+ *
+ * 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
+#include
+
+//===================================================================================================================================
+// 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 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
diff --git a/indra/llcommon/aifile.cpp b/indra/llcommon/aifile.cpp
new file mode 100644
index 000000000..c963f5109
--- /dev/null
+++ b/indra/llcommon/aifile.cpp
@@ -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 .
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution.
+ *
+ * CHANGELOG
+ * and additional copyright holders.
+ *
+ * 03/11/2013
+ * Initial version, written by Aleric Inglewood @ SL
+ */
+
+#include "linden_common.h"
+#include "aifile.h"
+#include "aialert.h"
+
+#if LL_WINDOWS
+#include
+#include // Windows errno
+#else
+#include
+#endif
+
+AIFile::AIFile(std::string const& filename, char const* accessmode)
+{
+ mFp = AIFile::fopen(filename, accessmode);
+}
+
+AIFile::~AIFile()
+{
+ AIFile::close(mFp);
+}
+
+// Like THROW_MALERTE but appends "LLFile::strerr(errn) << " (" << errn << ')'" as argument to replace [ERROR].
+#define THROW_ERROR(...) \
+ do { \
+ int errn = errno; \
+ std::ostringstream error; \
+ error << LLFile::strerr(errn) << " (" << errn << ')'; \
+ THROW_MALERT_CLASS(AIAlert::ErrorCode, errn, __VA_ARGS__ ("[ERROR]", error.str())); \
+ } while(0)
+
+//static
+void AIFile::mkdir(std::string const& dirname, int perms)
+{
+ int rc = LLFile::mkdir(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));
+ }
+}
+
diff --git a/indra/llcommon/aifile.h b/indra/llcommon/aifile.h
new file mode 100644
index 000000000..1b110496a
--- /dev/null
+++ b/indra/llcommon/aifile.h
@@ -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 .
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution.
+ *
+ * CHANGELOG
+ * and additional copyright holders.
+ *
+ * 02/11/2013
+ * Initial version, written by Aleric Inglewood @ SL
+ */
+
+#ifndef AIFILE_H
+#define AIFILE_H
+
+#include "llfile.h"
+
+// As LLFile, but throws AIAlert instead of printing a warning.
+class LL_COMMON_API AIFile
+{
+ private:
+ LLFILE* mFp;
+
+ public:
+ // Scoped file (exception safe). Throws AIAlertCode with errno on failure.
+ AIFile(std::string const& filename, char const* accessmode);
+ ~AIFile();
+
+ operator LLFILE* () const { return mFp; }
+
+ // All these functions take UTF8 path/filenames.
+ static LLFILE* fopen(std::string const& filename, char const* accessmode);
+ static void close(LLFILE* file);
+
+ static void mkdir(std::string const& dirname, int perms = 0700); // Does NOT throw when dirname already exists.
+ static void rmdir(std::string const& dirname); // Does NOT throw when dirname does not exist.
+ static void remove(std::string const& filename); // Does NOT throw when filename does not exist.
+ static void rename(std::string const& filename, std::string const& newname);
+};
+
+#endif // AIFILE_H
diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp
index e0e9d3a27..4a34ffaf9 100644
--- a/indra/llcommon/llfile.cpp
+++ b/indra/llcommon/llfile.cpp
@@ -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
diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h
index 12eb04932..1f5514f3e 100644
--- a/indra/llcommon/llfile.h
+++ b/indra/llcommon/llfile.h
@@ -30,6 +30,9 @@
#ifndef LL_LLFILE_H
#define LL_LLFILE_H
+#include
+#include
+
/**
* 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
-#include
-
#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();
};
/**
diff --git a/indra/llcommon/llmd5.cpp b/indra/llcommon/llmd5.cpp
index 1409c55d1..46775313d 100644
--- a/indra/llcommon/llmd5.cpp
+++ b/indra/llcommon/llmd5.cpp
@@ -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(){
diff --git a/indra/llcommon/llmd5.h b/indra/llcommon/llmd5.h
index 8bf715f14..8909f04d4 100644
--- a/indra/llcommon/llmd5.h
+++ b/indra/llcommon/llmd5.h
@@ -32,6 +32,10 @@
#ifndef LL_LLMD5_H
#define LL_LLMD5_H
+#include "llpreprocessor.h"
+#include
+#include // 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
diff --git a/indra/llcommon/llrefcount.h b/indra/llcommon/llrefcount.h
index b7831e7fa..4df84028a 100644
--- a/indra/llcommon/llrefcount.h
+++ b/indra/llcommon/llrefcount.h
@@ -27,6 +27,9 @@
#define LLREFCOUNT_H
#include
+#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
diff --git a/indra/llcommon/llrun.h b/indra/llcommon/llrun.h
index 1fc9925df..1701800b1 100644
--- a/indra/llcommon/llrun.h
+++ b/indra/llcommon/llrun.h
@@ -37,6 +37,8 @@
#include
#include
+#include "llpreprocessor.h"
+#include "stdtypes.h"
class LLRunnable;
diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h
index 78b8f95be..a780a6a24 100644
--- a/indra/llcommon/llsingleton.h
+++ b/indra/llcommon/llsingleton.h
@@ -27,6 +27,7 @@
#include "llerror.h" // *TODO: eliminate this
+#include