/*==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 . 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; iSelectNode(node,false); } else node = ip->GetRootNode(); for (int i=0; iNumberOfChildren(); 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 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; iNumberOfChildren(); 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; iNumberOfChildren(); 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; iIsRootNode() || 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; iGetSelNodeCount() == 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; iGetSelNodeCount(); 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(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 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); }