00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "nel/ligo/ligo_config.h"
00025
00026 #include "nel/ligo/primitive.h"
00027 #include "nel/misc/config_file.h"
00028 #include "nel/misc/i_xml.h"
00029 #include "nel/misc/path.h"
00030 #include "nel/misc/file.h"
00031
00032 #include <cstdlib>
00033
00034 using namespace std;
00035 using namespace NLMISC;
00036
00037 namespace NLLIGO
00038 {
00039
00040
00041 CLigoConfig::CLigoConfig()
00042 : _DynamicAliasBitCount(32)
00043 {
00044 }
00045
00046
00047
00048 bool CLigoConfig::readConfigFile (const char *fileName, bool parsePrimitiveComboContent)
00049 {
00050
00051 CConfigFile cf;
00052
00053
00054 cf.load (fileName);
00055
00056
00057 CConfigFile::CVar &cell_size = cf.getVar ("cell_size");
00058 CellSize = cell_size.asFloat ();
00059 CConfigFile::CVar &snap = cf.getVar ("snap");
00060 Snap = snap.asFloat ();
00061 CConfigFile::CVar &snapShot = cf.getVar ("zone_snapeshot_res");
00062 ZoneSnapShotRes = (uint)snapShot.asInt ();
00063 CConfigFile::CVar &primitiveClassFilename = cf.getVar ("primitive_class_filename");
00064 PrimitiveClassFilename= primitiveClassFilename.asString ();
00065
00066
00067 _Contexts.clear();
00068 _Contexts.push_back ("default");
00069 _PrimitiveClasses.clear();
00070 _PrimitiveConfigurations.clear();
00071
00072
00073 if (!PrimitiveClassFilename.empty())
00074 {
00075 return readPrimitiveClass (PrimitiveClassFilename.c_str(), parsePrimitiveComboContent);
00076 }
00077 return true;
00078 }
00079
00080
00081
00082 bool CLigoConfig::readPrimitiveClass (const char *_fileName, bool parsePrimitiveComboContent)
00083 {
00084
00085 string filename = _fileName;
00086 filename = CPath::lookup (_fileName, false, false, false);
00087 if (filename.empty())
00088 filename = _fileName;
00089
00090
00091 set<string> contextStrings;
00092
00093
00094 CIFile file;
00095 if (file.open (filename))
00096 {
00097 try
00098 {
00099
00100 CIXml xml;
00101 xml.init (file);
00102
00103
00104 xmlNodePtr root = xml.getRootNode ();
00105 nlassert (root);
00106
00107
00108 if (strcmp ((const char*)root->name, "NEL_LIGO_PRIMITIVE_CLASS") == 0)
00109 {
00110
00111 xmlNodePtr aliasBits = CIXml::getFirstChildNode (root, "ALIAS_DYNAMIC_BITS");
00112 if (aliasBits)
00113 {
00114 string bits;
00115 if (getPropertyString (bits, filename.c_str(), aliasBits, "BIT_COUNT"))
00116 {
00117 uint32 uBits;
00118 NLMISC::fromString(bits, uBits);
00119 _DynamicAliasBitCount = std::min((uint32)32, uBits);
00120 }
00121 else
00122 return false;
00123
00124 }
00125 else
00126 {
00127
00128 _DynamicAliasBitCount = 32;
00129 }
00130
00131 xmlNodePtr indexFileNameNode = CIXml::getFirstChildNode (root, "ALIAS_STATIC_FILE_ID");
00132 if (indexFileNameNode)
00133 {
00134 string indexFileName;
00135 if (getPropertyString (indexFileName, filename.c_str(), indexFileNameNode, "FILE_NAME"))
00136 {
00137 if (CPath::lookup(indexFileName, false, false, true).empty())
00138 {
00139
00140 indexFileName = CFile::getPath(_fileName)+indexFileName;
00141 }
00142
00143 reloadIndexFile(indexFileName);
00144 }
00145 else
00146 nlwarning("Can't find XML element <FILE_NAME>, no file index available for alias" );
00147 }
00148 else
00149 {
00150
00151 _DynamicAliasBitCount = 32;
00152 }
00153
00154
00155
00156 xmlNodePtr primitive = CIXml::getFirstChildNode (root, "PRIMITIVE");
00157 if (primitive)
00158 {
00159 do
00160 {
00161
00162 std::string name;
00163 if (getPropertyString (name, filename.c_str(), primitive, "CLASS_NAME"))
00164 {
00165
00166 pair<std::map<std::string, CPrimitiveClass>::iterator, bool> insertResult =
00167 _PrimitiveClasses.insert (std::map<std::string, CPrimitiveClass>::value_type (name, CPrimitiveClass ()));
00168 if (insertResult.second)
00169 {
00170 if (!insertResult.first->second.read (primitive, filename.c_str(), name.c_str (), contextStrings, _ContextFilesLookup, *this, parsePrimitiveComboContent))
00171 return false;
00172 }
00173 else
00174 {
00175 syntaxError (filename.c_str(), root, "Class (%s) already defined", name.c_str ());
00176 }
00177 }
00178 else
00179 return false;
00180
00181 primitive = CIXml::getNextChildNode (primitive, "PRIMITIVE");
00182 }
00183 while (primitive);
00184 }
00185
00186
00187 {
00188 set<string>::iterator ite = contextStrings.begin ();
00189 while (ite != contextStrings.end ())
00190 {
00191 if (*ite != "default")
00192 _Contexts.push_back (*ite);
00193 ite++;
00194 }
00195 }
00196
00197
00198 _PrimitiveConfigurations.reserve (_PrimitiveConfigurations.size()+CIXml::countChildren (root, "CONFIGURATION"));
00199 xmlNodePtr configuration = CIXml::getFirstChildNode (root, "CONFIGURATION");
00200 if (configuration)
00201 {
00202 do
00203 {
00204
00205 std::string name;
00206 if (getPropertyString (name, filename.c_str(), configuration, "NAME"))
00207 {
00208
00209 _PrimitiveConfigurations.resize (_PrimitiveConfigurations.size()+1);
00210 if (!_PrimitiveConfigurations.back().read (configuration, filename.c_str(), name.c_str (), *this))
00211 return false;
00212 }
00213 else
00214 return false;
00215
00216 configuration = CIXml::getNextChildNode (configuration, "CONFIGURATION");
00217 }
00218 while (configuration);
00219 }
00220
00221
00222 return true;
00223 }
00224 else
00225 {
00226 syntaxError (filename.c_str(), root, "Wrong root node, should be NEL_LIGO_PRIMITIVE_CLASS");
00227 }
00228 }
00229 catch (Exception &e)
00230 {
00231 errorMessage ("File read error (%s):%s", filename.c_str(), e.what ());
00232 }
00233 }
00234 else
00235 {
00236 errorMessage ("Can't open the file %s for reading.", filename.c_str());
00237 }
00238 return false;
00239 }
00240
00241
00242
00243 bool CLigoConfig::reloadIndexFile(const std::string &indexFileName)
00244 {
00245 if (_IndexFileName.empty() && indexFileName.empty())
00246 {
00247 nlwarning("CLigoConfig::reloadIndexFile: no file name specified and index file not previously loaded, can't load anything");
00248 return false;
00249 }
00250
00251 if (!_IndexFileName.empty() && !indexFileName.empty() && _IndexFileName != indexFileName)
00252 {
00253 nlwarning("CLigoConfig::reloadIndexFile: index file already loaded as '%s', can't load another file '%s'!",
00254 _IndexFileName.c_str(),
00255 indexFileName.c_str());
00256 return false;
00257 }
00258
00259 if (_IndexFileName.empty())
00260 _IndexFileName = indexFileName;
00261
00262
00263 CConfigFile cf;
00264 string pathName = CPath::lookup(_IndexFileName, false);
00265
00266 if (pathName.empty())
00267 {
00268 nlwarning("Can't find index file '%s' in search path, no file index available for alias", indexFileName.c_str());
00269 return false;
00270 }
00271 cf.load(pathName);
00272
00273
00274 CConfigFile::CVar *files = cf.getVarPtr("Files");
00275 if (files != NULL)
00276 {
00277 for (uint i=0; i<files->size()/2; ++i)
00278 {
00279 string fileName;
00280 uint32 index;
00281
00282 fileName = files->asString(i*2);
00283 index = files->asInt(i*2+1);
00284
00285 if (isFileStaticAliasMapped(fileName))
00286 {
00287
00288 if (getFileStaticAliasMapping(fileName) != index)
00289 {
00290 nlwarning("CLigoConfig::reloadIndexFile: the mapping for the file '%s' as changed from %u to %u in the config file, the change is ignored",
00291 fileName.c_str(),
00292 index,
00293 getFileStaticAliasMapping(fileName));
00294 }
00295 }
00296 else
00297 {
00298 registerFileToStaticAliasTranslation(fileName, index);
00299 }
00300 }
00301 }
00302
00303 return true;
00304 }
00305
00306
00307
00308 NLMISC::CRGBA CLigoConfig::getPrimitiveColor (const NLLIGO::IPrimitive &primitive)
00309 {
00310
00311 string className;
00312 if (primitive.getPropertyByName ("class", className))
00313 {
00314
00315 std::map<std::string, CPrimitiveClass>::iterator ite = _PrimitiveClasses.find (className);
00316 if (ite != _PrimitiveClasses.end ())
00317 {
00318 return ite->second.Color;
00319 }
00320 }
00321 return DEFAULT_PRIMITIVE_COLOR;
00322 }
00323
00324
00325
00326 bool CLigoConfig::isPrimitiveLinked (const NLLIGO::IPrimitive &primitive)
00327 {
00328
00329 string className;
00330 if (primitive.getPropertyByName ("class", className))
00331 {
00332
00333 std::map<std::string, CPrimitiveClass>::iterator ite = _PrimitiveClasses.find (className);
00334 if (ite != _PrimitiveClasses.end ())
00335 {
00336 return ite->second.LinkBrothers;
00337 }
00338 }
00339 return false;
00340 }
00341
00342
00343
00344 const NLLIGO::IPrimitive *CLigoConfig::getLinkedPrimitive (const NLLIGO::IPrimitive &primitive) const
00345 {
00346
00347 const IPrimitive *parent = primitive.getParent ();
00348 if (parent)
00349 {
00350 uint childId;
00351 if (parent->getChildId (childId, &primitive))
00352 {
00353
00354
00355
00356 string className;
00357 if (primitive.getPropertyByName ("class", className))
00358 {
00359
00360 std::map<std::string, CPrimitiveClass>::const_iterator ite = _PrimitiveClasses.find (className);
00361 if (ite != _PrimitiveClasses.end ())
00362 {
00363 if (ite->second.LinkBrothers)
00364 {
00365
00366 const IPrimitive *brother;
00367 if (parent->getChild (brother, childId+1))
00368 return brother;
00369 }
00370 }
00371 }
00372 }
00373 }
00374 return NULL;
00375 }
00376
00377
00378
00379 const NLLIGO::IPrimitive *CLigoConfig::getPreviousLinkedPrimitive (const NLLIGO::IPrimitive &primitive) const
00380 {
00381
00382 const IPrimitive *parent = primitive.getParent ();
00383 if (parent)
00384 {
00385 uint childId;
00386 if (parent->getChildId (childId, &primitive))
00387 {
00388
00389 if (childId > 0)
00390 {
00391 const IPrimitive *brother;
00392 if (parent->getChild (brother, childId-1) && brother)
00393 {
00394
00395 string className;
00396 if (brother->getPropertyByName ("class", className))
00397 {
00398
00399 std::map<std::string, CPrimitiveClass>::const_iterator ite = _PrimitiveClasses.find (className);
00400 if (ite != _PrimitiveClasses.end ())
00401 {
00402 if (ite->second.LinkBrothers)
00403 {
00404
00405 return brother;
00406 }
00407 }
00408 }
00409 }
00410 }
00411 }
00412 }
00413 return NULL;
00414 }
00415
00416
00417
00418 bool CLigoConfig::isPrimitiveDeletable (const NLLIGO::IPrimitive &primitive)
00419 {
00420
00421 if (isStaticChild (primitive))
00422 return false;
00423
00424
00425 string className;
00426 if (primitive.getPropertyByName ("class", className))
00427 {
00428
00429 std::map<std::string, CPrimitiveClass>::iterator ite = _PrimitiveClasses.find (className);
00430 if (ite != _PrimitiveClasses.end ())
00431 {
00432 return ite->second.Deletable;
00433 }
00434 }
00435 return false;
00436 }
00437
00438
00439
00440 bool CLigoConfig::canBeChild (const NLLIGO::IPrimitive &child, const NLLIGO::IPrimitive &parent)
00441 {
00442
00443 string childClassName;
00444 if (child.getPropertyByName ("class", childClassName))
00445 {
00446
00447 const CPrimitiveClass *parentClass = getPrimitiveClass (parent);
00448 if (parentClass)
00449 {
00450
00451 uint i;
00452 for (i=0; i<parentClass->DynamicChildren.size (); i++)
00453 {
00454
00455 if (parentClass->DynamicChildren[i].ClassName == childClassName)
00456 break;
00457 }
00458
00459 if (i<parentClass->DynamicChildren.size ())
00460 return true;
00461
00462 for (i=0; i<parentClass->GeneratedChildren.size (); i++)
00463 {
00464
00465 if (parentClass->GeneratedChildren[i].ClassName == childClassName)
00466 break;
00467 }
00468
00469 return (i<parentClass->GeneratedChildren.size ());
00470 }
00471 else
00472 return true;
00473 }
00474 else
00475 {
00476
00477 string parentClassName;
00478 return ( (parent.getParent () == NULL) || (!parent.getPropertyByName ("class", parentClassName) ) );
00479 }
00480 }
00481
00482
00483
00484 bool CLigoConfig::canBeRoot (const NLLIGO::IPrimitive &child)
00485 {
00486
00487 string childClassName;
00488 if (child.getPropertyByName ("class", childClassName))
00489 {
00490
00491 const CPrimitiveClass *parentClass = getPrimitiveClass ("root");
00492 if (parentClass)
00493 {
00494
00495 uint i;
00496 for (i=0; i<parentClass->DynamicChildren.size (); i++)
00497 {
00498
00499 if (parentClass->DynamicChildren[i].ClassName == childClassName)
00500 break;
00501 }
00502
00503 return (i<parentClass->DynamicChildren.size ());
00504 }
00505 else
00506 return true;
00507 }
00508 else
00509 {
00510
00511 return ( !getPrimitiveClass ("root") );
00512 }
00513 }
00514
00515
00516
00517 bool CLigoConfig::getPropertyString (std::string &result, const char *filename, xmlNodePtr xmlNode, const char *propName)
00518 {
00519
00520 if (!CIXml::getPropertyString (result, xmlNode, propName))
00521 {
00522
00523 syntaxError (filename, xmlNode, "Missing XML node property (%s)", propName);
00524 return false;
00525 }
00526 return true;
00527 }
00528
00529
00530
00531 void CLigoConfig::syntaxError (const char *filename, xmlNodePtr xmlNode, const char *format, ...)
00532 {
00533 va_list args;
00534 va_start( args, format );
00535 char buffer[1024];
00536 vsnprintf( buffer, 1024, format, args );
00537 va_end( args );
00538
00539 errorMessage ("(%s), node (%s), line (%d) :\n%s", filename, xmlNode->name, (ptrdiff_t)xmlNode->content, buffer);
00540 }
00541
00542
00543
00544 void CLigoConfig::errorMessage (const char *format, ... )
00545 {
00546
00547 va_list args;
00548 va_start( args, format );
00549 char buffer[1024];
00550 vsnprintf( buffer, 1024, format, args );
00551 va_end( args );
00552
00553 nlwarning (buffer);
00554 }
00555
00556
00557
00558 const std::vector<std::string> &CLigoConfig::getContextString () const
00559 {
00560 return _Contexts;
00561 }
00562
00563
00564
00565 const CPrimitiveClass *CLigoConfig::getPrimitiveClass (const IPrimitive &primitive) const
00566 {
00567 const CPrimitiveClass *primClass = NULL;
00568
00569
00570 string className;
00571 if (primitive.getPropertyByName ("class", className))
00572 {
00573 std::map<std::string, CPrimitiveClass>::const_iterator ite = _PrimitiveClasses.find (className);
00574 if (ite != _PrimitiveClasses.end ())
00575 {
00576 primClass = &(ite->second);
00577 }
00578 }
00579
00580
00581 if (!primClass)
00582 {
00583
00584 if (!primitive.getParent ())
00585 {
00586 std::map<std::string, CPrimitiveClass>::const_iterator ite = _PrimitiveClasses.find ("root");
00587 if (ite != _PrimitiveClasses.end ())
00588 {
00589 primClass = &(ite->second);
00590 }
00591 }
00592 }
00593 return primClass;
00594 }
00595
00596
00597
00598 const CPrimitiveClass *CLigoConfig::getPrimitiveClass (const char *className) const
00599 {
00600 std::map<std::string, CPrimitiveClass>::const_iterator ite = _PrimitiveClasses.find (className);
00601 if (ite != _PrimitiveClasses.end ())
00602 {
00603 return &(ite->second);
00604 }
00605 return NULL;
00606 }
00607
00608
00609
00610 void CLigoConfig::resetPrimitiveConfiguration ()
00611 {
00612 _PrimitiveConfigurations.clear ();
00613 }
00614
00615
00616
00617 bool CLigoConfig::isStaticChild (const NLLIGO::IPrimitive &primitive)
00618 {
00619
00620 const IPrimitive *parent = primitive.getParent ();
00621 if (parent)
00622 {
00623
00624 const CPrimitiveClass *parentClass = getPrimitiveClass (*parent);
00625 string className;
00626 string name;
00627 if (parentClass && primitive.getPropertyByName ("class", className) && primitive.getPropertyByName ("name", name))
00628 {
00629
00630 uint i;
00631 for (i=0; i<parentClass->StaticChildren.size(); i++)
00632 {
00633 if (parentClass->StaticChildren[i].Name == name &&
00634 parentClass->StaticChildren[i].ClassName == className)
00635 {
00636
00637 return true;
00638 }
00639 }
00640 }
00641 }
00642 return false;
00643 }
00644
00645
00646
00648 uint32 CLigoConfig::getDynamicAliasSize() const
00649 {
00650 return _DynamicAliasBitCount;
00651 }
00652
00653
00655 uint32 CLigoConfig::getDynamicAliasMask() const
00656 {
00657
00658
00659
00660 if (_DynamicAliasBitCount >= 32)
00661 return 0xffffffff;
00662 else
00663 return (1U<<_DynamicAliasBitCount)-1;
00664 }
00665
00666
00668 uint32 CLigoConfig::getStaticAliasSize() const
00669 {
00670 return 32-_DynamicAliasBitCount;
00671 }
00672
00673
00675 uint32 CLigoConfig::getStaticAliasMask() const
00676 {
00677
00678 return ~getDynamicAliasMask();
00679 }
00680
00681
00683 uint32 CLigoConfig::buildAlias(uint32 staticPart, uint32 dynamicPart, bool warnIfOverload) const
00684 {
00685 if (warnIfOverload)
00686 {
00687 if (staticPart != (staticPart & (getStaticAliasMask()>>getDynamicAliasSize())))
00688 {
00689 nlwarning("CLigoConfig::buildAlias: staticPart 0x%x is outside the mask 0x%x",
00690 staticPart,
00691 getStaticAliasMask()>>getDynamicAliasSize());
00692 }
00693 if (dynamicPart != (dynamicPart & getDynamicAliasMask()))
00694 {
00695 nlwarning("CLigoConfig::buildAlias: dynamicPart 0x%x is outside the mask 0x%x",
00696 dynamicPart,
00697 getDynamicAliasMask());
00698 }
00699 }
00700
00701 return dynamicPart | (staticPart << _DynamicAliasBitCount);
00702 }
00703
00704
00705
00706 void CLigoConfig::registerFileToStaticAliasTranslation(const std::string &fileName, uint32 staticPart)
00707 {
00708
00709 std::map<std::string, uint32>::iterator first(_StaticAliasFileMapping.begin()), last(_StaticAliasFileMapping.end());
00710 for (; first != last; ++first)
00711 {
00712 if (first->second == staticPart)
00713 {
00714 nlassertex(false, ("While registering static alias %u to file '%s', the alias is already assigned to file '%s'",
00715 staticPart,
00716 fileName.c_str(),
00717 first->first.c_str()));
00718 }
00719 }
00720 if ((staticPart<<getDynamicAliasSize()) != ((staticPart<<getDynamicAliasSize()) & getStaticAliasMask()))
00721 {
00722 nlwarning("CLigoConfig::registerStaticAliasTranslation: staticPart 0x%x(%u) is outside the mask 0x%x, the staticPart will be clipped to 0x%x(%u)",
00723 staticPart,
00724 staticPart,
00725 getStaticAliasMask(),
00726 staticPart & getStaticAliasMask(),
00727 staticPart & getStaticAliasMask());
00728
00729 staticPart = (staticPart & getStaticAliasMask());
00730 }
00731
00732
00733 _StaticAliasFileMapping[fileName] = staticPart;
00734 }
00735
00736 const std::string &CLigoConfig::getFileNameForStaticAlias(uint32 staticAlias) const
00737 {
00738 std::map<std::string, uint32>::const_iterator first(_StaticAliasFileMapping.begin()), last(_StaticAliasFileMapping.end());
00739
00740 for (; first != last; ++first)
00741 {
00742 if (first->second == staticAlias)
00743 return first->first;
00744 }
00745 static string emptyString;
00746
00747 return emptyString;
00748 }
00749
00750
00751
00752
00753 uint32 CLigoConfig::getFileStaticAliasMapping(const std::string &fileName) const
00754 {
00755 std::map<std::string, uint32>::const_iterator it(_StaticAliasFileMapping.find(fileName));
00756
00757 if (it != _StaticAliasFileMapping.end())
00758 {
00759 return it->second;
00760 }
00761 else
00762
00763 return 0;
00764 }
00765
00766
00767
00768 bool CLigoConfig::isFileStaticAliasMapped(const std::string &fileName) const
00769 {
00770 std::map<std::string, uint32>::const_iterator it(_StaticAliasFileMapping.find(fileName));
00771
00772 if (it != _StaticAliasFileMapping.end())
00773 {
00774 return true;
00775 }
00776 else
00777
00778 return false;
00779 }
00780
00781
00782 std::string CLigoConfig::aliasToString(uint32 fullAlias)
00783 {
00784 uint32 staticPart;
00785 uint32 dynPart;
00786
00787 staticPart = (fullAlias & getStaticAliasMask())>>getDynamicAliasSize();
00788 dynPart = fullAlias & getDynamicAliasMask();
00789
00790 return toString("(A:%u:%u)", staticPart, dynPart);
00791
00792 }
00793
00794 uint32 CLigoConfig::aliasFromString(std::string fullAlias)
00795 {
00796 uint32 staticPart;
00797 uint32 dynPart;
00798 sscanf(fullAlias.c_str(), "(A:%u:%u)", &staticPart, &dynPart);
00799
00800 return ((staticPart<<getDynamicAliasSize()) & getStaticAliasMask()) | (dynPart & getDynamicAliasMask());
00801
00802 }
00803
00804
00805 void CLigoConfig::updateDynamicAliasBitCount(uint32 newDynamicAliasBitCount)
00806 {
00807 sint32 diff = _DynamicAliasBitCount - newDynamicAliasBitCount;
00808
00809 if (diff <= 0)
00810 {
00811 nlwarning("New bit count must be less than previous");
00812 nlassert(0);
00813
00814 }
00815
00816 std::map<std::string, uint32>::iterator first(_StaticAliasFileMapping.begin()), last(_StaticAliasFileMapping.end());
00817 for ( ; first != last; ++first)
00818 {
00819 first->second = first->second << diff;
00820 }
00821 _DynamicAliasBitCount = newDynamicAliasBitCount;
00822 }
00823
00824
00825 }
00826
00827