You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

870 lines
22 KiB

/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
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 3 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/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
// UserPropMgr.cpp
#include "hsTypes.h"
#include "UserPropMgr.h"
#include "hsStringTokenizer.h"
#include "hsUtils.h"
#include "hsHashTable.h"
#define REFMSG_USERPROP (REFMSG_USER + 1)
const UInt32 UserPropMgr::kQuickSize = 150001;//199999;
UserPropMgr gUserPropMgr(GetCOREInterface());
UserPropMgr::UserPropMgr(Interface *ip) :
nm(0)
{
this->ip = ip;
fQuickTable = nil;
fQuickNode = nil;
vProps = false;
}
UserPropMgr::~UserPropMgr()
{
CloseQuickTable();
}
void UserPropMgr::SetUserPropFlag(INode *node, const char *name, const BOOL setFlag, const Int32 hFlag)
{
if (setFlag) SetUserProp(node,name,NULL,hFlag);
else ClearUserProp(node,name,hFlag);
}
void UserPropMgr::ClearUserPropALL(const char *name, const Int32 hFlag)
{
for (int i=0; i<GetSelNodeCount(); i++)
{
ClearUserProp(GetSelNode(i),name,hFlag);
}
}
void UserPropMgr::SelectUserPropFlagALL(INode *node, const char *name, const BOOL flag) {
if (node)
{
if (UserPropExists(node,name) == flag) ip->SelectNode(node,false);
} else node = ip->GetRootNode();
for (int i=0; i<node->NumberOfChildren(); i++) {
SelectUserPropFlagALL(node->GetChildNode(i),name,flag);
}
}
void UserPropMgr::DeSelectWithOut(const char *name, const char *value) {
BOOL oldProps = vProps;
vProps=false;
TSTR val;
INode *nodes[1];
INodeTab nodeTab;
for (int i=0; i<GetSelNodeCount(); i++) {
if (value) {
if (!(GetUserProp(GetSelNode(i),name,val) && !stricmp(val,value))) {
nodes[0] = GetSelNode(i);
nodeTab.Append(1,nodes);
}
} else if (!UserPropExists(GetSelNode(i),name)) {
nodes[0] = GetSelNode(i);
nodeTab.Append(1,nodes);
}
}
vProps=oldProps;
if (nodeTab.Count() > 0) ip->SelectNodeTab(nodeTab,false,false);
}
void UserPropMgr::RecursiveSelectAll(INode *node) {
if (node) {
if (!node->Selected()) ip->SelectNode(node,false);
} else node = ip->GetRootNode();
for (int i=0; i<node->NumberOfChildren(); i++) {
RecursiveSelectAll(node->GetChildNode(i));
}
}
void UserPropMgr::DeSelectUnAlike(INode *node) {
theHold.Begin();
ip->ThawSelection();
RecursiveSelectAll();
TSTR buf;
GetUserPropBuffer(node,buf);
hsStringTokenizer toker(buf," \r\n");
toker.ParseQuotes(TRUE);
char *tok;
TSTR name;
bool isName = true;
while (tok=toker.next()) {
if (isName) {
if (*tok != '=') {
name = tok;
tok = toker.next();
if (tok && *tok == '=') {
tok = toker.next();
} else tok = NULL;
DeSelectWithOut(name,tok);
} else isName = false;
} else {
isName = true;
}
}
TSTR undostr; undostr.printf("Select");
theHold.Accept(undostr);
ip->FreezeSelection();
ip->RedrawViews(ip->GetTime());
}
int UserPropMgr::RecursiveCountAlike(INode *node, BOOL MatchAll) {
int count=0;
if (node) {
if (!node->IsNodeHidden() && !node->IsFrozen() && IsAlike(node,MatchAll)) count++;
} else node = ip->GetRootNode();
for (int i=0; i<node->NumberOfChildren(); i++) {
count += RecursiveCountAlike(node->GetChildNode(i),MatchAll);
}
return count;
}
int UserPropMgr::CountAlike(BOOL MatchAll) {
return RecursiveCountAlike(NULL, MatchAll);
}
BOOL UserPropMgr::IsMatch(const char *val1, const char *val2) {
if (!stricmp(val1,val2)) return true;
hsStringTokenizer toker(val1," ,@");
char *tok;
while (tok=toker.next()) {
hsStringTokenizer toker2(val2," ,@");
BOOL found = false;
char *tok2;
while ((tok2=toker2.next()) && !found) {
if (tok[0] >= '1' && tok[0] <= '0') {
if (!stricmp(tok,tok2)) found = true;
} else if (toker.HasMoreTokens()) {
if (!stricmp(tok,tok2)) found = true;if (!stricmp(tok,tok2)) found = true;
} else {
if (!strnicmp(tok,tok2,strlen(tok))) found = true;
}
}
if (!found) return false;
}
return true;
}
BOOL UserPropMgr::IsAlike(INode *node, BOOL MatchAll) {
TSTR buf;
GetUserPropBuffer(node,buf);
BOOL oldProps = vProps;
vProps=false;
hsStringTokenizer toker(buf," \r\n");
toker.ParseQuotes(TRUE);
char *tok;
TSTR name;
TSTR value;
TSTR tval;
BOOL match = MatchAll;
bool isName = true;
tok = toker.next();
while (tok && (match==MatchAll)) {
if (isName) {
if (*tok != '=') {
name = tok;
tok = toker.next();
if (tok && *tok == '=') {
tok = toker.next();
if (tok) value = tok;
else value = "";
tok = toker.next();
} else value = "";
if (GetUserProp(node,name,tval)) match = IsMatch(value,tval);
else match = false;
continue;
} else isName = false;
} else {
isName = true;
}
tok=toker.next();
}
if (match==MatchAll) {
if (!vname.isNull()) match = IsMatch(vname,node->GetName());
}
vProps = oldProps;
return match;
}
int UserPropMgr::GetUserPropCount(INode *node) {
TSTR buf;
GetUserPropBuffer(node,buf);
int numProps = 0;
hsStringTokenizer toker(buf," \r\n");
toker.ParseQuotes(TRUE);
char *tok;
bool isName = true;
while (tok=toker.next()) {
if (isName) {
if (*tok != '=') {
numProps++;
} else isName = false;
} else {
isName = true;
}
}
return numProps;
}
void UserPropMgr::GetUserPropBuffer(INode *node, TSTR &buf) {
if (vProps) buf = vbuf;
else if (node) node->GetUserPropBuffer(buf);
else buf = "";
}
void UserPropMgr::SetUserPropBuffer(INode *node, const TSTR &buf)
{
// QuickTable invalidate
if (node && node == fQuickNode)
{
fQuickNode = nil;
}
if (vProps)
{
vbuf = buf;
}
else if (node)
{
node->SetUserPropBuffer(buf);
node->NotifyDependents(FOREVER, PART_ALL, REFMSG_USERPROP);
}
}
void UserPropMgr::SetUserPropFlagALL(const char *name, const BOOL setFlag, const Int32 hFlag)
{
for (int i=0; i<GetSelNodeCount();i++)
{
SetUserPropFlag(GetSelNode(i),name,setFlag,hFlag);
}
}
BOOL UserPropMgr::GetUserPropFlagALL(const char *name, BOOL &isSet, const Int32 hFlag)
{
isSet = UserPropMgr::UserPropExists(GetSelNode(0),name,hFlag);
for (int i=0; i<GetSelNodeCount(); i++) {
if (isSet != UserPropMgr::UserPropExists(GetSelNode(i),name,hFlag)) return FALSE;
}
return TRUE;
}
INode* UserPropMgr::GetAncestorIfNeeded(INode* node, const Int32 hFlag)
{
if (hFlag == kParent)
{
if (!(node->IsRootNode() || node->GetParentNode()->IsRootNode()))
node = node->GetParentNode();
}
else
if (hFlag == kRoot)
{
while (!(node->IsRootNode() || node->GetParentNode()->IsRootNode()))
node = node->GetParentNode();
}
return node;
}
void UserPropMgr::ClearUserProp(INode *node, const char *name, const Int32 hFlag)
{
node = GetAncestorIfNeeded(node,hFlag);
// QuickTable invalidate
if (node && node == fQuickNode)
{
fQuickNode = nil;
}
TSTR buf;
GetUserPropBuffer(node,buf);
hsStringTokenizer toker(buf," \r\n");
toker.ParseQuotes(TRUE);
char *tok;
bool isName = true;
while (tok=toker.next())
{
if (isName)
{
if (*tok != '=')
{
if (!stricmp(tok,name))
{
char *tok2 = toker.next();
if (tok2)
{
if (*tok2 == '=')
{
tok2 = toker.next();
if (tok2)
{
tok2 = toker.next();
if (tok2)
{
buf.remove(tok-toker.fString,tok2-tok);
}
else
{
buf.remove(tok-toker.fString);
}
}
else
{
buf.remove(tok-toker.fString);
}
}
else
{
buf.remove(tok-toker.fString,tok2-tok);
}
}
else
{
buf.remove(tok-toker.fString);
}
break;
}
}
else
{
isName = false;
}
}
else
{
isName = true;
}
}
if (vProps)
{
vbuf = buf;
}
else
{
node->SetUserPropBuffer(buf);
node->NotifyDependents(FOREVER, PART_ALL, REFMSG_USERPROP);
}
};
BOOL UserPropMgr::GetUserProp(INode *node, const char *name, TSTR &value, const Int32 hFlag)
{
node = GetAncestorIfNeeded(node,hFlag);
// QuickTable lookup
if (node && fQuickTable)
{
if (node != fQuickNode)
IBuildQuickTable(node);
return ICheckQuickEntry(name,value);
}
TSTR buf;
GetUserPropBuffer(node,buf);
hsStringTokenizer toker(buf," \r\n");
toker.ParseQuotes(TRUE);
char *tok;
bool isName = true;
while (tok=toker.next())
{
if (isName)
{
if (*tok != '=')
{
if (!stricmp(tok,name))
{
tok = toker.next();
if (tok && *tok == '=')
{
tok = toker.next();
if (tok) value = tok;
else value = "";
return true;
}
else
{
value = "";
return true;
}
}
}
else
isName = false;
}
else
{
isName = true;
}
}
return false;
}
void UserPropMgr::SetUserProp(INode *node, const char *name, const char *value, const Int32 hFlag)
{
node = GetAncestorIfNeeded(node,hFlag);
// QuickTable invalidate
if (node && node == fQuickNode)
{
fQuickNode = nil;
}
TSTR buf;
GetUserPropBuffer(node,buf);
hsStringTokenizer toker(buf," \r\n");
toker.ParseQuotes(TRUE);
char *tok;
bool isName = true;
while (tok=toker.next())
{
if (isName)
{
if (*tok != '=')
{
if (!stricmp(tok,name))
{
char *tok2 = toker.next();
if (tok2)
{
if (*tok2 == '=')
{
tok2 = toker.next();
if (tok2)
{
tok2 = toker.next();
if (tok2)
{
buf.remove(tok-toker.fString,tok2-tok);
}
else
{
buf.remove(tok-toker.fString);
}
}
else
{
buf.remove(tok-toker.fString);
}
}
else
{
buf.remove(tok-toker.fString,tok2-tok);
}
}
else
{
buf.remove(tok-toker.fString);
}
break;
}
}
else
{
isName = false;
}
}
else
{
isName = true;
}
}
if (buf.last('\n') < buf.length()-1)
{
// better start with a separator
buf += "\r\n";
}
buf += name;
if (value && *value)
{
buf += " = ";
if (strchr(value,' '))
{
buf += "\"";
buf += value;
buf += "\"";
}
else
{
buf += value;
}
}
buf += "\r\n";
if (vProps)
{
vbuf = buf;
}
else
{
node->SetUserPropBuffer(buf);
node->NotifyDependents(FOREVER, PART_ALL, REFMSG_USERPROP);
}
}
BOOL UserPropMgr::GetUserPropString(INode *node, const char *name, TSTR &value, const Int32 hFlag)
{
return GetUserProp(node,name,value,hFlag);
}
void UserPropMgr::SetUserPropString(INode *node, const char *name, const char *value, const Int32 hFlag)
{
SetUserProp(node,name,value,hFlag);
}
BOOL UserPropMgr::GetUserPropFloat(INode *node, const char *name, float &value, const Int32 hFlag)
{
TSTR valStr;
if (GetUserProp(node,name,valStr,hFlag))
{
value = (float)atof(valStr);
return TRUE;
}
return FALSE;
}
void UserPropMgr::SetUserPropFloat(INode *node, const char *name, const float value, const Int32 hFlag)
{
char valStr[50];
if (sprintf(valStr,"%g",value)) SetUserProp(node,name,valStr,hFlag);
}
BOOL UserPropMgr::GetUserPropInt(INode *node, const char *name, int &value, const Int32 hFlag)
{
TSTR valStr;
if (GetUserProp(node,name,valStr,hFlag)) {
value = atoi(valStr);
return TRUE;
}
return FALSE;
}
void UserPropMgr::SetUserPropInt(INode *node, const char *name, const int value, const Int32 hFlag)
{
char valStr[50];
if (sprintf(valStr,"%d",value)) SetUserProp(node,name,valStr,hFlag);
}
BOOL UserPropMgr::UserPropExists(INode *node, const char *name, const Int32 hFlag)
{
TSTR value;
return GetUserProp(node,name,value,hFlag);
}
BOOL UserPropMgr::GetUserPropStringList(INode *node, const char *name, int &num, TSTR list[]) {
TSTR sdata;
if (UserPropMgr::GetUserPropString(node,name,sdata)) {
num=0;
hsStringTokenizer toker(sdata,", ");
char *tok;
while ( tok = toker.next() ) {
list[num] = tok;
num++;
}
return true;
} else return false;
}
BOOL UserPropMgr::GetUserPropIntList(INode *node, const char *name, int &num, int list[]) {
TSTR sdata;
if (UserPropMgr::GetUserPropString(node,name,sdata)) {
num=0;
hsStringTokenizer toker(sdata,", ");
char *tok;
while ( tok = toker.next() ) {
list[num] = atoi(tok);
num++;
}
return true;
} else return false;
}
BOOL UserPropMgr::GetUserPropFloatList(INode *node, const char *name, int &num, float list[]) {
TSTR sdata;
if (UserPropMgr::GetUserPropString(node,name,sdata)) {
num=0;
hsStringTokenizer toker(sdata,", ");
char *tok;
while ( tok = toker.next() ) {
list[num] = (float)atof(tok);
num++;
}
return true;
} else return false;
}
BOOL UserPropMgr::GetUserPropStringALL(const char *name, TSTR &value, const Int32 hFlag)
{
BOOL propSet = UserPropMgr::GetUserPropString(GetSelNode(0),name,value,hFlag);
TSTR tvalue;
int i=1;
BOOL propMixed = FALSE;
while (i < GetSelNodeCount() && !propMixed) {
if (propSet ^ UserPropMgr::GetUserPropString(GetSelNode(i),name,tvalue,hFlag)) propMixed = TRUE;
propMixed = (!(value == tvalue));
i++;
}
return (!propMixed);
}
void UserPropMgr::SetUserPropStringALL(const char *name, const char *value, const Int32 hFlag)
{
for (int i=0; i<GetSelNodeCount(); i++) {
UserPropMgr::SetUserPropString(GetSelNode(i),name,value,hFlag);
}
}
BOOL UserPropMgr::GetUserPropStringListALL(const char *name, int &num, TSTR list[]) {
TSTR val;
GetUserPropStringList(GetSelNode(0),name,num,list);
return GetUserPropStringALL(name,val);
}
BOOL UserPropMgr::GetUserPropIntListALL(const char *name, int &num, int *list) {
TSTR val;
GetUserPropIntList(GetSelNode(0),name,num,list);
return GetUserPropStringALL(name,val);
}
BOOL UserPropMgr::GetUserPropFloatListALL(const char *name, int &num, float *list) {
TSTR val;
GetUserPropFloatList(GetSelNode(0),name,num,list);
return GetUserPropStringALL(name,val);
}
BOOL UserPropMgr::GetNodeNameALL(TSTR &name) {
if (vProps) name = vname;
else if (ip->GetSelNodeCount() == 1) name = ip->GetSelNode(0)->GetName();
else return false;
return true;
}
void UserPropMgr::SetNodeNameALL(const char *name) {
if (vProps) {
vname = name;
} else {
if (ip->GetSelNodeCount() > 1) {
TSTR uName;
for (int i=0; i<ip->GetSelNodeCount(); i++) {
uName = name;
ip->MakeNameUnique(uName);
ip->GetSelNode(i)->SetName(uName);
}
} else ip->GetSelNode(0)->SetName((char*)name);
}
}
void UserPropMgr::LoadVirtualProps(BOOL reset) {
if (reset)
{
vbuf = "";
vname = "";
}
vProps = true;
}
void UserPropMgr::DestroyVirtualProps() {
vProps = false;
}
BOOL UserPropMgr::IsVirtual() {
return vProps;
}
int UserPropMgr::GetSelNodeCount() {
if (vProps) return 1;
else return ip->GetSelNodeCount();
}
INode *UserPropMgr::GetSelNode(int i) {
if (vProps) return NULL;
else return ip->GetSelNode(i);
}
void UserPropMgr::OpenQuickTable()
{
if (!fQuickTable)
{
fQuickTable = TRACKED_NEW hsHashTable<QuickPair>(kQuickSize);
}
fQuickNode = nil;
}
void UserPropMgr::CloseQuickTable()
{
#ifdef HS_DEBUGGING
if (fQuickNode && fQuickTable)
{
char str[256];
sprintf(str,"%d Hash Collisions reported\n",fQuickTable->CollisionCount());
hsStatusMessage(str);
}
#endif
delete fQuickTable;
fQuickTable = nil;
fQuickNode = nil;
QuickPair::SetBuffer(nil);
}
void UserPropMgr::IBuildQuickTable(INode* node)
{
if (fQuickTable && fQuickNode != node)
{
fQuickNode = node;
// clear old QuickTable
fQuickTable->clear();
// build new one
TSTR buf;
GetUserPropBuffer(node,buf);
hsStringTokenizer toker(buf," \r\n");
toker.ParseQuotes(TRUE);
char *tok;
bool inName = false;
bool isName = true;
while ( inName || (tok=toker.next()) )
{
if (isName)
{
if (*tok != '=')
{
QuickPair qPair;
qPair.SetKey(tok);
tok = toker.next();
if (tok && *tok == '=')
{
tok = toker.next();
qPair.SetVal(tok);
inName = false;
}
else
{
qPair.SetVal(nil);
inName = (tok != 0);
}
fQuickTable->insert(qPair);
}
else
{
isName = false;
}
}
else
{
isName = true;
}
}
// QuickPair owns the tok'd buffer now
QuickPair::SetBuffer(toker.fString);
toker.fString = nil;
}
}
BOOL UserPropMgr::ICheckQuickEntry(const char *key, TSTR &value)
{
QuickPair q;
q.SetKey(key);
hsHashTableIterator<QuickPair> it = fQuickTable->find(q);
return it->GetVal(value);
}
char* UserPropMgr::QuickPair::fBuffer = nil;
void UserPropMgr::QuickPair::SetBuffer(char* buf)
{
delete [] fBuffer;
fBuffer = buf;
}
UInt32 UserPropMgr::QuickPair::GetHash() const
{
const char * k = fKey;
int len = k ? strlen(k) : 0;
int h;
for (h=len; len--;)
{
h = ((h<<5)^(h>>27))^tolower(*k++);
}
return h;
}
hsBool UserPropMgr::QuickPair::GetVal(TSTR& value)
{
if (fKey)
{
value = fVal ? fVal : "";
return true;
}
else
{
return false;
}
}
bool UserPropMgr::QuickPair::operator==(const QuickPair& other) const
{
return !_stricmp(fKey,other.fKey);
}