Code owners
Assign users and groups as approvers for specific file changes. Learn more.
llnamevalue.cpp 20.77 KiB
/**
* @file llnamevalue.cpp
* @brief class for defining name value pairs.
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
// Examples:
// AvatarCharacter STRING RW DSV male1
#include "linden_common.h"
#include "llnamevalue.h"
#include "u64.h"
#include "llstring.h"
#include "llstringtable.h"
#if LL_GNUC
#pragma GCC diagnostic ignored "-Wstringop-truncation"
#endif
// Anonymous enumeration to provide constants in this file.
// *NOTE: These values may be used in sscanf statements below as their
// value-1, so search for '2047' if you cange NV_BUFFER_LEN or '63' if
// you change U64_BUFFER_LEN.
enum
{
NV_BUFFER_LEN = 2048,
U64_BUFFER_LEN = 64
};
LLStringTable gNVNameTable(256);
char NameValueTypeStrings[NVT_EOF][NAME_VALUE_TYPE_STRING_LENGTH] = /*Flawfinder: Ignore*/
{
"NULL",
"STRING",
"F32",
"S32",
"VEC3",
"U32",
"CAMERA", // Deprecated, but leaving in case removing completely would cause problems
"ASSET",
"U64"
};
char NameValueClassStrings[NVC_EOF][NAME_VALUE_CLASS_STRING_LENGTH] = /*Flawfinder: Ignore*/
{
"NULL",
"R", // read only
"RW" // read write
};
char NameValueSendtoStrings[NVS_EOF][NAME_VALUE_SENDTO_STRING_LENGTH] = /*Flawfinder: Ignore*/
{
"NULL",
"S", // "Sim", formerly SIM
"DS", // "Data Sim" formerly SIM_SPACE
"SV", // "Sim Viewer" formerly SIM_VIEWER
"DSV" // "Data Sim Viewer", formerly SIM_SPACE_VIEWER
}; /*Flawfinder: Ignore*/
//
// Class
//
LLNameValue::LLNameValue()
{
baseInit();
}
void LLNameValue::baseInit()
{
mNVNameTable = &gNVNameTable;
mName = NULL;
mNameValueReference.string = NULL;
mType = NVT_NULL;
mStringType = NameValueTypeStrings[NVT_NULL];
mClass = NVC_NULL;
mStringClass = NameValueClassStrings[NVC_NULL];
mSendto = NVS_NULL;
mStringSendto = NameValueSendtoStrings[NVS_NULL];
}
void LLNameValue::init(const char *name, const char *data, const char *type, const char *nvclass, const char *nvsendto)
{
mNVNameTable = &gNVNameTable;
mName = mNVNameTable->addString(name);
// Nota Bene: Whatever global structure manages this should have these in the name table already!
mStringType = mNVNameTable->addString(type);
if (!strcmp(mStringType, "STRING"))
{
S32 string_length = (S32)strlen(data); /*Flawfinder: Ignore*/
mType = NVT_STRING;
delete[] mNameValueReference.string;
// two options here. . . data can either look like foo or "foo"
// WRONG! - this is a poorly implemented and incomplete escape
// mechanism. For example, using this scheme, there is no way
// to tell an intentional double quotes from a zero length
// string. This needs to excised. Phoenix
//if (strchr(data, '\"'))
//{
// string_length -= 2;
// mNameValueReference.string = new char[string_length + 1];;
// strncpy(mNameValueReference.string, data + 1, string_length);
//}
//else
//{
mNameValueReference.string = new char[string_length + 1];;
strncpy(mNameValueReference.string, data, string_length); /*Flawfinder: Ignore*/
//}
mNameValueReference.string[string_length] = 0;
}
else if (!strcmp(mStringType, "F32"))
{
mType = NVT_F32;
mNameValueReference.f32 = new F32((F32)atof(data));
}
else if (!strcmp(mStringType, "S32"))
{
mType = NVT_S32;
mNameValueReference.s32 = new S32(atoi(data));
}
else if (!strcmp(mStringType, "U64"))
{
mType = NVT_U64;
mNameValueReference.u64 = new U64(str_to_U64(ll_safe_string(data)));
}
else if (!strcmp(mStringType, "VEC3"))
{
mType = NVT_VEC3;
F32 t1, t2, t3;
// two options here. . . data can either look like 0, 1, 2 or <0, 1, 2>
if (strchr(data, '<'))
{
sscanf(data, "<%f, %f, %f>", &t1, &t2, &t3);
}
else
{
sscanf(data, "%f, %f, %f", &t1, &t2, &t3);
}
// finite checks
if (!llfinite(t1) || !llfinite(t2) || !llfinite(t3))
{
t1 = 0.f;
t2 = 0.f;
t3 = 0.f;
}
mNameValueReference.vec3 = new LLVector3(t1, t2, t3);
}
else if (!strcmp(mStringType, "U32"))
{
mType = NVT_U32;
mNameValueReference.u32 = new U32(atoi(data));
}
else if(!strcmp(mStringType, (const char*)NameValueTypeStrings[NVT_ASSET]))
{
// assets are treated like strings, except that the name has
// meaning to an LLAssetInfo object
S32 string_length = (S32)strlen(data); /*Flawfinder: Ignore*/
mType = NVT_ASSET;
// two options here. . . data can either look like foo or "foo"
// WRONG! - this is a poorly implemented and incomplete escape
// mechanism. For example, using this scheme, there is no way
// to tell an intentional double quotes from a zero length
// string. This needs to excised. Phoenix
//if (strchr(data, '\"'))
//{
// string_length -= 2;
// mNameValueReference.string = new char[string_length + 1];;
// strncpy(mNameValueReference.string, data + 1, string_length);
//}
//else
//{
mNameValueReference.string = new char[string_length + 1];;
strncpy(mNameValueReference.string, data, string_length); /*Flawfinder: Ignore*/
//}
mNameValueReference.string[string_length] = 0;
}
else
{
LL_WARNS() << "Unknown name value type string " << mStringType << " for " << mName << LL_ENDL;
mType = NVT_NULL;
}
// Nota Bene: Whatever global structure manages this should have these in the name table already!
if (!strcmp(nvclass, "R") ||
!strcmp(nvclass, "READ_ONLY")) // legacy
{
mClass = NVC_READ_ONLY;
mStringClass = mNVNameTable->addString("R");
}
else if (!strcmp(nvclass, "RW") ||
!strcmp(nvclass, "READ_WRITE")) // legacy
{
mClass = NVC_READ_WRITE;
mStringClass = mNVNameTable->addString("RW");
}
else
{
// assume it's bad
mClass = NVC_NULL;
mStringClass = mNVNameTable->addString(nvclass);
}
// Initialize the sendto variable
if (!strcmp(nvsendto, "S") ||
!strcmp(nvsendto, "SIM")) // legacy
{
mSendto = NVS_SIM;
mStringSendto = mNVNameTable->addString("S");
}
else if (!strcmp(nvsendto, "DS") ||
!strcmp(nvsendto, "SIM_SPACE")) // legacy
{
mSendto = NVS_DATA_SIM;
mStringSendto = mNVNameTable->addString("DS");
}
else if (!strcmp(nvsendto, "SV") ||
!strcmp(nvsendto, "SIM_VIEWER")) // legacy
{
mSendto = NVS_SIM_VIEWER;
mStringSendto = mNVNameTable->addString("SV");
}
else if (!strcmp(nvsendto, "DSV") ||
!strcmp(nvsendto, "SIM_SPACE_VIEWER")) // legacy
{
mSendto = NVS_DATA_SIM_VIEWER;
mStringSendto = mNVNameTable->addString("DSV");
}
else
{
LL_WARNS() << "LLNameValue::init() - unknown sendto field "
<< nvsendto << " for NV " << mName << LL_ENDL;
mSendto = NVS_NULL;
mStringSendto = mNVNameTable->addString("S");
}
}
LLNameValue::LLNameValue(const char *name, const char *data, const char *type, const char *nvclass)
{
baseInit();
// if not specified, send to simulator only
init(name, data, type, nvclass, "SIM");
}
LLNameValue::LLNameValue(const char *name, const char *data, const char *type, const char *nvclass, const char *nvsendto)
{
baseInit();
init(name, data, type, nvclass, nvsendto);
}
// Initialize without any initial data.
LLNameValue::LLNameValue(const char *name, const char *type, const char *nvclass)
{
baseInit();
mName = mNVNameTable->addString(name);
// Nota Bene: Whatever global structure manages this should have these in the name table already!
mStringType = mNVNameTable->addString(type);
if (!strcmp(mStringType, "STRING"))
{
mType = NVT_STRING;
mNameValueReference.string = NULL;
}
else if (!strcmp(mStringType, "F32"))
{
mType = NVT_F32;
mNameValueReference.f32 = NULL;
}
else if (!strcmp(mStringType, "S32"))
{
mType = NVT_S32;
mNameValueReference.s32 = NULL;
}
else if (!strcmp(mStringType, "VEC3"))
{
mType = NVT_VEC3;
mNameValueReference.vec3 = NULL;
}
else if (!strcmp(mStringType, "U32"))
{
mType = NVT_U32;
mNameValueReference.u32 = NULL;
}
else if (!strcmp(mStringType, "U64"))
{
mType = NVT_U64;
mNameValueReference.u64 = NULL;
}
else if(!strcmp(mStringType, (const char*)NameValueTypeStrings[NVT_ASSET]))
{
mType = NVT_ASSET;
mNameValueReference.string = NULL;
}
else
{
mType = NVT_NULL;
LL_INFOS() << "Unknown name-value type " << mStringType << LL_ENDL;
}
// Nota Bene: Whatever global structure manages this should have these in the name table already!
mStringClass = mNVNameTable->addString(nvclass);
if (!strcmp(mStringClass, "READ_ONLY"))
{
mClass = NVC_READ_ONLY;
}
else if (!strcmp(mStringClass, "READ_WRITE"))
{
mClass = NVC_READ_WRITE;
}
else
{
mClass = NVC_NULL;
}
// Initialize the sendto variable
mStringSendto = mNVNameTable->addString("SIM");
mSendto = NVS_SIM;
}
// data is in the format:
// "NameValueName Type Class Data"
LLNameValue::LLNameValue(const char *data)
{
baseInit();
static char name[NV_BUFFER_LEN]; /*Flawfinder: ignore*/
static char type[NV_BUFFER_LEN]; /*Flawfinder: ignore*/
static char nvclass[NV_BUFFER_LEN]; /*Flawfinder: ignore*/
static char nvsendto[NV_BUFFER_LEN]; /*Flawfinder: ignore*/
static char nvdata[NV_BUFFER_LEN]; /*Flawfinder: ignore*/
S32 i;
S32 character_count = 0;
S32 length = 0;
// go to first non-whitespace character
while (1)
{
if ( (*(data + character_count) == ' ')
||(*(data + character_count) == '\n')
||(*(data + character_count) == '\t')
||(*(data + character_count) == '\r'))
{
character_count++;
}
else
{
break;
}
}
// read in the name
sscanf((data + character_count), "%2047s", name); /*Flawfinder: ignore*/
// bump past it and add null terminator
length = (S32)strlen(name); /* Flawfinder: ignore */
name[length] = 0;
character_count += length;
// go to the next non-whitespace character
while (1)
{
if ( (*(data + character_count) == ' ')
||(*(data + character_count) == '\n')
||(*(data + character_count) == '\t')
||(*(data + character_count) == '\r'))
{
character_count++;
}
else
{
break;
}
}
// read in the type
sscanf((data + character_count), "%2047s", type); /*Flawfinder: ignore*/
// bump past it and add null terminator
length = (S32)strlen(type); /* Flawfinder: ignore */
type[length] = 0;
character_count += length;
// go to the next non-whitespace character
while (1)
{
if ( (*(data + character_count) == ' ')
||(*(data + character_count) == '\n')
||(*(data + character_count) == '\t')
||(*(data + character_count) == '\r'))
{
character_count++;
}
else
{
break;
}
}
// do we have a type argument?
for (i = NVC_READ_ONLY; i < NVC_EOF; i++)
{
if (!strncmp(NameValueClassStrings[i], data + character_count, strlen(NameValueClassStrings[i]))) /* Flawfinder: ignore */
{
break;
}
}
if (i != NVC_EOF)
{
// yes we do!
// read in the class
sscanf((data + character_count), "%2047s", nvclass); /*Flawfinder: ignore*/
// bump past it and add null terminator
length = (S32)strlen(nvclass); /* Flawfinder: ignore */
nvclass[length] = 0;
character_count += length;
// go to the next non-whitespace character
while (1)
{
if ( (*(data + character_count) == ' ')
||(*(data + character_count) == '\n')
||(*(data + character_count) == '\t')
||(*(data + character_count) == '\r'))
{
character_count++;
}
else
{
break;
}
}
}
else
{
// no type argument given, default to read-write
strncpy(nvclass, "READ_WRITE", sizeof(nvclass) -1); /* Flawfinder: ignore */
nvclass[sizeof(nvclass) -1] = '\0';
}
// Do we have a sendto argument?
for (i = NVS_SIM; i < NVS_EOF; i++)
{
if (!strncmp(NameValueSendtoStrings[i], data + character_count, strlen(NameValueSendtoStrings[i]))) /* Flawfinder: ignore */
{
break;
}
}
if (i != NVS_EOF)
{
// found a sendto argument
sscanf((data + character_count), "%2047s", nvsendto); /*Flawfinder: ignore*/
// add null terminator
length = (S32)strlen(nvsendto); /* Flawfinder: ignore */
nvsendto[length] = 0;
character_count += length;
// seek to next non-whitespace characer
while (1)
{
if ( (*(data + character_count) == ' ')
||(*(data + character_count) == '\n')
||(*(data + character_count) == '\t')
||(*(data + character_count) == '\r'))
{
character_count++;
}
else
{
break;
}
}
}
else
{
// no sendto argument given, default to sim only
strncpy(nvsendto, "SIM", sizeof(nvsendto) -1); /* Flawfinder: ignore */
nvsendto[sizeof(nvsendto) -1] ='\0';
}
// copy the rest character by character into data
length = 0;
while ( (*(nvdata + length++) = *(data + character_count++)) )
;
init(name, nvdata, type, nvclass, nvsendto);
}
LLNameValue::~LLNameValue()
{
mNVNameTable->removeString(mName);
mName = NULL;
switch(mType)
{
case NVT_STRING:
case NVT_ASSET:
delete [] mNameValueReference.string;
mNameValueReference.string = NULL;
break;
case NVT_F32:
delete mNameValueReference.f32;
mNameValueReference.string = NULL;
break;
case NVT_S32:
delete mNameValueReference.s32;
mNameValueReference.string = NULL;
break;
case NVT_VEC3:
delete mNameValueReference.vec3;
mNameValueReference.string = NULL;
break;
case NVT_U32:
delete mNameValueReference.u32;
mNameValueReference.u32 = NULL;
break;
case NVT_U64:
delete mNameValueReference.u64;
mNameValueReference.u64 = NULL;
break;
default:
break;
}
delete[] mNameValueReference.string;
mNameValueReference.string = NULL;
}
char *LLNameValue::getString()
{
if (mType == NVT_STRING)
{
return mNameValueReference.string;
}
else
{
LL_ERRS() << mName << " not a string!" << LL_ENDL;
return NULL;
}
}
const char *LLNameValue::getAsset() const
{
if (mType == NVT_ASSET)
{
return mNameValueReference.string;
}
else
{
LL_ERRS() << mName << " not an asset!" << LL_ENDL;
return NULL;
}
}
F32 *LLNameValue::getF32()
{
if (mType == NVT_F32)
{
return mNameValueReference.f32;
}
else
{
LL_ERRS() << mName << " not a F32!" << LL_ENDL;
return NULL;
}
}
S32 *LLNameValue::getS32()
{
if (mType == NVT_S32)
{
return mNameValueReference.s32;
}
else
{
LL_ERRS() << mName << " not a S32!" << LL_ENDL;
return NULL;
}
}
U32 *LLNameValue::getU32()
{
if (mType == NVT_U32)
{
return mNameValueReference.u32;
}
else
{
LL_ERRS() << mName << " not a U32!" << LL_ENDL;
return NULL;
}
}
U64 *LLNameValue::getU64()
{
if (mType == NVT_U64)
{
return mNameValueReference.u64;
}
else
{
LL_ERRS() << mName << " not a U64!" << LL_ENDL;
return NULL;
}
}
void LLNameValue::getVec3(LLVector3 &vec)
{
if (mType == NVT_VEC3)
{
vec = *mNameValueReference.vec3;
}
else
{
LL_ERRS() << mName << " not a Vec3!" << LL_ENDL;
}
}
LLVector3 *LLNameValue::getVec3()
{
if (mType == NVT_VEC3)
{
return (mNameValueReference.vec3);
}
else
{
LL_ERRS() << mName << " not a Vec3!" << LL_ENDL;
return NULL;
}
}
BOOL LLNameValue::sendToData() const
{
return (mSendto == NVS_DATA_SIM || mSendto == NVS_DATA_SIM_VIEWER);
}
BOOL LLNameValue::sendToViewer() const
{
return (mSendto == NVS_SIM_VIEWER || mSendto == NVS_DATA_SIM_VIEWER);
}
LLNameValue &LLNameValue::operator=(const LLNameValue &a)
{
if (mType != a.mType)
{
return *this;
}
if (mClass == NVC_READ_ONLY)
return *this;
switch(a.mType)
{
case NVT_STRING:
case NVT_ASSET:
if (mNameValueReference.string)
delete [] mNameValueReference.string;
mNameValueReference.string = new char [strlen(a.mNameValueReference.string) + 1]; /* Flawfinder: ignore */
if(mNameValueReference.string != NULL)
{
strcpy(mNameValueReference.string, a.mNameValueReference.string); /* Flawfinder: ignore */
}
break;
case NVT_F32:
*mNameValueReference.f32 = *a.mNameValueReference.f32;
break;
case NVT_S32:
*mNameValueReference.s32 = *a.mNameValueReference.s32;
break;
case NVT_VEC3:
*mNameValueReference.vec3 = *a.mNameValueReference.vec3;
break;
case NVT_U32:
*mNameValueReference.u32 = *a.mNameValueReference.u32;
break;
case NVT_U64:
*mNameValueReference.u64 = *a.mNameValueReference.u64;
break;
default:
LL_ERRS() << "Unknown Name value type " << (U32)a.mType << LL_ENDL;
break;
}
return *this;
}
void LLNameValue::setString(const char *a)
{
if (mClass == NVC_READ_ONLY)
return;
switch(mType)
{
case NVT_STRING:
if (a)
{
if (mNameValueReference.string)
{
delete [] mNameValueReference.string;
}
mNameValueReference.string = new char [strlen(a) + 1]; /* Flawfinder: ignore */
if(mNameValueReference.string != NULL)
{
strcpy(mNameValueReference.string, a); /* Flawfinder: ignore */
}
}
else
{
if (mNameValueReference.string)
delete [] mNameValueReference.string;
mNameValueReference.string = new char [1];
mNameValueReference.string[0] = 0;
}
break;
default:
break;
}
return;
}
void LLNameValue::setAsset(const char *a)
{
if (mClass == NVC_READ_ONLY)
return;
switch(mType)
{
case NVT_ASSET:
if (a)
{
if (mNameValueReference.string)
{
delete [] mNameValueReference.string;
}
mNameValueReference.string = new char [strlen(a) + 1]; /* Flawfinder: ignore */
if(mNameValueReference.string != NULL)
{
strcpy(mNameValueReference.string, a); /* Flawfinder: ignore */
}
}
else
{
if (mNameValueReference.string)
delete [] mNameValueReference.string;
mNameValueReference.string = new char [1];
mNameValueReference.string[0] = 0;
}
break;
default:
break;
}
}
void LLNameValue::setF32(const F32 a)
{
if (mClass == NVC_READ_ONLY)
return;
switch(mType)
{
case NVT_F32:
*mNameValueReference.f32 = a;
break;
default:
break;
}
return;
}
void LLNameValue::setS32(const S32 a)
{
if (mClass == NVC_READ_ONLY)
return;
switch(mType)
{
case NVT_S32:
*mNameValueReference.s32 = a;
break;
case NVT_U32:
*mNameValueReference.u32 = a;
break;
case NVT_F32:
*mNameValueReference.f32 = (F32)a;
break;
default:
break;
}
return;
}
void LLNameValue::setU32(const U32 a)
{
if (mClass == NVC_READ_ONLY)
return;
switch(mType)
{
case NVT_S32:
*mNameValueReference.s32 = a;
break;
case NVT_U32:
*mNameValueReference.u32 = a;
break;
case NVT_F32:
*mNameValueReference.f32 = (F32)a;
break;
default:
LL_ERRS() << "NameValue: Trying to set U32 into a " << mStringType << ", unknown conversion" << LL_ENDL;
break;
}
return;
}
void LLNameValue::setVec3(const LLVector3 &a)
{
if (mClass == NVC_READ_ONLY)
return;
switch(mType)
{
case NVT_VEC3:
*mNameValueReference.vec3 = a;
break;
default:
LL_ERRS() << "NameValue: Trying to set LLVector3 into a " << mStringType << ", unknown conversion" << LL_ENDL;
break;
}
return;
}
std::string LLNameValue::printNameValue() const
{
std::string buffer;
buffer = llformat("%s %s %s %s ", mName, mStringType, mStringClass, mStringSendto);
buffer += printData();
// LL_INFOS() << "Name Value Length: " << buffer.size() + 1 << LL_ENDL;
return buffer;
}
std::string LLNameValue::printData() const
{
std::string buffer;
switch(mType)
{
case NVT_STRING:
case NVT_ASSET:
buffer = mNameValueReference.string;
break;
case NVT_F32:
buffer = llformat("%f", *mNameValueReference.f32);
break;
case NVT_S32:
buffer = llformat("%d", *mNameValueReference.s32);
break;
case NVT_U32:
buffer = llformat("%u", *mNameValueReference.u32);
break;
case NVT_U64:
{
char u64_string[U64_BUFFER_LEN]; /* Flawfinder: ignore */
U64_to_str(*mNameValueReference.u64, u64_string, sizeof(u64_string));
buffer = u64_string;
}
break;
case NVT_VEC3:
buffer = llformat( "%f, %f, %f", mNameValueReference.vec3->mV[VX], mNameValueReference.vec3->mV[VY], mNameValueReference.vec3->mV[VZ]);
break;
default:
LL_ERRS() << "Trying to print unknown NameValue type " << mStringType << LL_ENDL;
break;
}
return buffer;
}
std::ostream& operator<<(std::ostream& s, const LLNameValue &a)
{
switch(a.mType)
{
case NVT_STRING:
case NVT_ASSET:
s << a.mNameValueReference.string;
break;
case NVT_F32:
s << (*a.mNameValueReference.f32);
break;
case NVT_S32:
s << *(a.mNameValueReference.s32);
break;
case NVT_U32:
s << *(a.mNameValueReference.u32);
break;
case NVT_U64:
{
char u64_string[U64_BUFFER_LEN]; /* Flawfinder: ignore */
U64_to_str(*a.mNameValueReference.u64, u64_string, sizeof(u64_string));
s << u64_string;
}
break;
case NVT_VEC3:
s << *(a.mNameValueReference.vec3);
break;
default:
LL_ERRS() << "Trying to print unknown NameValue type " << a.mStringType << LL_ENDL;
break;
}
return s;
}