00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifndef NL_LOAD_FORM_H
00025 #define NL_LOAD_FORM_H
00026
00027 #include "nel/misc/types_nl.h"
00028
00029 #include <map>
00030 #include <string>
00031 #include <vector>
00032
00033 #include "nel/misc/path.h"
00034 #include "nel/misc/file.h"
00035 #include "nel/misc/sheet_id.h"
00036 #include "nel/misc/algo.h"
00037
00038 #include "u_form_loader.h"
00039 #include "u_form.h"
00040
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119 const uint32 PACKED_SHEET_HEADER = 'PKSH';
00120 const uint32 PACKED_SHEET_VERSION = 5;
00121
00122 const uint32 PACKED_SHEET_VERSION_COMPATIBLE = 0;
00123
00124
00130 template <class T>
00131 void loadForm (const std::vector<std::string> &sheetFilters, const std::string &packedFilename, std::map<NLMISC::CSheetId, T> &container, bool updatePackedSheet=true, bool errorIfPackedSheetNotGood=true)
00132 {
00133 std::vector<std::string> dictionnary;
00134 std::map<std::string, uint> dictionnaryIndex;
00135 std::map<NLMISC::CSheetId, std::vector<uint32> > dependencies;
00136 std::vector<uint32> dependencyDates;
00137
00138
00139 nlassert (packedFilename.find (".packed_sheets") != std::string::npos);
00140
00141 std::string packedFilenamePath = NLMISC::CPath::lookup(NLMISC::CFile::getFilename(packedFilename), false, false);
00142 if (packedFilenamePath.empty())
00143 {
00144 packedFilenamePath = packedFilename;
00145 }
00146
00147
00148 NLMISC::CSheetId::init(updatePackedSheet);
00149
00150
00151 try
00152 {
00153 NLMISC::CIFile ifile;
00154 ifile.setCacheFileOnOpen(true);
00155 if (!ifile.open (packedFilenamePath))
00156 {
00157 throw NLMISC::Exception("can't open PackedSheet %s", packedFilenamePath.c_str());
00158 }
00159
00160
00161 nlinfo ("loadForm(): Loading packed file '%s'", packedFilename.c_str());
00162
00163
00164 ifile.serialCheck(PACKED_SHEET_HEADER);
00165 ifile.serialCheck(PACKED_SHEET_VERSION);
00166 ifile.serialVersion(PACKED_SHEET_VERSION_COMPATIBLE);
00167
00168
00169 uint32 dependBlockSize;
00170 ifile.serial(dependBlockSize);
00171
00172
00173 if(updatePackedSheet)
00174 {
00175
00176 {
00177 ifile.serialCont(dictionnary);
00178 }
00179
00180 {
00181 uint32 depSize;
00182 ifile.serial(depSize);
00183 for (uint i=0; i<depSize; ++i)
00184 {
00185 NLMISC::CSheetId sheetId;
00186
00187
00188 ifile.serial(sheetId);
00189 ifile.serialCont(dependencies[sheetId]);
00190 }
00191 }
00192 }
00193
00194 else if(dependBlockSize>0)
00195 {
00196 std::vector<uint8> bigBlock;
00197 bigBlock.resize(dependBlockSize);
00198 ifile.serialBuffer(&bigBlock[0], dependBlockSize);
00199 }
00200
00201
00202 uint32 nbEntries;
00203 uint32 ver;
00204 ifile.serial (nbEntries);
00205 ifile.serial (ver);
00206 if(ver != T::getVersion ())
00207 throw NLMISC::Exception("The packed sheet version in stream is different of the code");
00208 ifile.serialCont (container);
00209 ifile.close ();
00210 }
00211 catch (NLMISC::Exception &e)
00212 {
00213
00214 container.clear ();
00215 if (!updatePackedSheet)
00216 {
00217 if (errorIfPackedSheetNotGood)
00218 nlerror ("loadForm(): Exception during reading the packed file and can't reconstruct them (%s)", e.what());
00219 else
00220 nlinfo ("loadForm(): Exception during reading the packed file and can't reconstruct them (%s)", e.what());
00221
00222 return;
00223 }
00224 else
00225 {
00226 nlinfo ("loadForm(): Exception during reading the packed file, I'll reconstruct it (%s)", e.what());
00227 }
00228 }
00229
00230
00231 if (!updatePackedSheet)
00232 {
00233 nlinfo ("Don't update the packed sheet with real sheet");
00234 return;
00235 }
00236
00237
00238 {
00239 for (uint i=0; i<dictionnary.size(); ++i)
00240 {
00241 std::string p = NLMISC::CPath::lookup (dictionnary[i], false, false);
00242 if (!p.empty())
00243 {
00244 uint32 d = NLMISC::CFile::getFileModificationDate(p);
00245 dependencyDates.push_back(d);
00246 }
00247 else
00248 {
00249
00250
00251 nldebug("Can't find dependent file %s !", dictionnary[i].c_str());
00252 dependencyDates.push_back(0xffffffff);
00253 }
00254 }
00255 }
00256
00257
00258 std::vector<NLMISC::CSheetId> sheetIds;
00259 std::vector<std::string> filenames;
00260 for (uint i = 0; i < sheetFilters.size(); i++)
00261 NLMISC::CSheetId::buildIdVector(sheetIds, filenames, sheetFilters[i]);
00262
00263
00264 if (sheetIds.empty())
00265 return;
00266
00267
00268 std::map<NLMISC::CSheetId, bool> sheetToRemove;
00269 for (typename std::map<NLMISC::CSheetId, T>::iterator it = container.begin(); it != container.end(); it++)
00270 {
00271 sheetToRemove.insert (std::make_pair((*it).first, true));
00272 }
00273
00274
00275 uint32 packedFiledate = NLMISC::CFile::getFileModificationDate(packedFilenamePath);
00276
00277 bool containerChanged = false;
00278
00279 NLGEORGES::UFormLoader *formLoader = NULL;
00280
00281 std::vector<uint> NeededToRecompute;
00282
00283 for (uint k = 0; k < filenames.size(); k++)
00284 {
00285 std::string p = NLMISC::CPath::lookup (filenames[k], false, false);
00286 if (p.empty()) continue;
00287 uint32 d = NLMISC::CFile::getFileModificationDate(p);
00288
00289
00290 sheetToRemove[sheetIds[k]] = false;
00291
00292 if( d > packedFiledate || container.find (sheetIds[k]) == container.end())
00293 {
00294 NeededToRecompute.push_back(k);
00295 }
00296 else
00297 {
00298
00299 nlassert(dependencies.find(sheetIds[k]) != dependencies.end());
00300 std::vector<uint32> &depends = dependencies[sheetIds[k]];
00301
00302 for (uint i=0; i<depends.size(); ++i)
00303 {
00304 if (dependencyDates[depends[i]] > packedFiledate)
00305 {
00306 nldebug("Dependency on %s for %s not up to date !",
00307 dictionnary[depends[i]].c_str(), sheetIds[k].toString().c_str());
00308 NeededToRecompute.push_back(k);
00309 break;
00310 }
00311 }
00312 }
00313 }
00314
00315 nlinfo ("%d sheets checked, %d need to be recomputed", filenames.size(), NeededToRecompute.size());
00316
00317 NLMISC::TTime last = NLMISC::CTime::getLocalTime ();
00318 NLMISC::TTime start = NLMISC::CTime::getLocalTime ();
00319
00320 NLMISC::CSmartPtr<NLGEORGES::UForm> form;
00321 std::vector<NLMISC::CSmartPtr<NLGEORGES::UForm> > cacheFormList;
00322
00323 for (uint j = 0; j < NeededToRecompute.size(); j++)
00324 {
00325 if(NLMISC::CTime::getLocalTime () > last + 5000)
00326 {
00327 last = NLMISC::CTime::getLocalTime ();
00328 if(j>0)
00329 nlinfo ("%.0f%% completed (%d/%d), %d seconds remaining", (float)j*100.0/NeededToRecompute.size(),j,NeededToRecompute.size(), (NeededToRecompute.size()-j)*(last-start)/j/1000);
00330 }
00331
00332
00333 if (formLoader == NULL)
00334 {
00335 NLMISC::WarningLog->addNegativeFilter("CFormLoader: Can't open the form file");
00336 formLoader = NLGEORGES::UFormLoader::createLoader ();
00337 }
00338
00339
00340 if (form)
00341 cacheFormList.push_back (form);
00342
00343
00344 form = formLoader->loadForm (sheetIds[NeededToRecompute[j]].toString().c_str ());
00345 if (form)
00346 {
00347
00348 {
00349 std::vector<uint32> depends;
00350 std::set<std::string> dependFiles;
00351 form->getDependencies (dependFiles);
00352 nlassert(dependFiles.find(sheetIds[NeededToRecompute[j]].toString()) != dependFiles.end());
00353
00354 dependFiles.erase(sheetIds[NeededToRecompute[j]].toString());
00355
00356 std::set<std::string>::iterator first(dependFiles.begin()), last(dependFiles.end());
00357 for (; first != last; ++first)
00358 {
00359 const std::string filename = NLMISC::CFile::getFilename(*first);
00360 std::map<std::string,uint>::iterator findDicIt=dictionnaryIndex.find(filename);
00361
00362 if (findDicIt!=dictionnaryIndex.end())
00363 {
00364 depends.push_back(findDicIt->second);
00365 continue;
00366 }
00367
00368 std::string p = NLMISC::CPath::lookup (*first, false, false);
00369 if (!p.empty())
00370 {
00371 uint dicIndex;
00372
00373 dicIndex = dictionnary.size();
00374 dictionnaryIndex.insert(std::make_pair(filename, dictionnary.size()));
00375 dictionnary.push_back(filename);
00376
00377
00378 depends.push_back(dicIndex);
00379 }
00380 }
00381
00382 dependencies[sheetIds[NeededToRecompute[j]]] = depends;
00383 }
00384
00385
00386 typedef typename std::map<NLMISC::CSheetId, T>::iterator TType1;
00387 typedef typename std::pair<TType1, bool> TType2;
00388 TType2 res = container.insert(std::make_pair(sheetIds[NeededToRecompute[j]],T()));
00389
00390 (*res.first).second.readGeorges (form, sheetIds[NeededToRecompute[j]]);
00391 containerChanged = true;
00392 }
00393 }
00394
00395 if(NeededToRecompute.size() > 0)
00396 nlinfo ("%d seconds to recompute %d sheets", (uint32)(NLMISC::CTime::getLocalTime()-start)/1000, NeededToRecompute.size());
00397
00398
00399 if (formLoader != NULL)
00400 {
00401 NLGEORGES::UFormLoader::releaseLoader (formLoader);
00402 NLMISC::WarningLog->removeFilter ("CFormLoader: Can't open the form file");
00403 }
00404
00405
00406 for (std::map<NLMISC::CSheetId, bool>::iterator it2 = sheetToRemove.begin(); it2 != sheetToRemove.end(); it2++)
00407 {
00408 if((*it2).second)
00409 {
00410 nlinfo ("the sheet '%s' is not in the directory, remove it from container", (*it2).first.toString().c_str());
00411 container.find((*it2).first)->second.removed();
00412 container.erase((*it2).first);
00413 containerChanged = true;
00414 dependencies.erase((*it2).first);
00415 }
00416 }
00417
00418
00419 try
00420 {
00421 if(containerChanged)
00422 {
00423 NLMISC::COFile ofile;
00424 ofile.open(packedFilenamePath);
00425
00426
00427 ofile.serialCheck(PACKED_SHEET_HEADER);
00428 ofile.serialCheck(PACKED_SHEET_VERSION);
00429 ofile.serialVersion(PACKED_SHEET_VERSION_COMPATIBLE);
00430
00431
00432 sint32 posBlockSize= ofile.getPos();
00433 uint32 dependBlockSize= 0;
00434 ofile.serial(dependBlockSize);
00435
00436
00437 ofile.serialCont(dictionnary);
00438
00439
00440 uint32 depSize = dependencies.size();
00441 ofile.serial(depSize);
00442 std::map<NLMISC::CSheetId, std::vector<uint32> >::iterator first(dependencies.begin()), last(dependencies.end());
00443 for (; first != last; ++first)
00444 {
00445 NLMISC::CSheetId si = first->first;
00446 ofile.serial(si);
00447 ofile.serialCont(first->second);
00448 }
00449
00450
00451 sint32 endBlockSize= ofile.getPos();
00452 dependBlockSize= (endBlockSize - posBlockSize) - 4;
00453 ofile.seek(posBlockSize, NLMISC::IStream::begin);
00454 ofile.serial(dependBlockSize);
00455 ofile.seek(endBlockSize, NLMISC::IStream::begin);
00456
00457
00458 uint32 nbEntries = sheetIds.size();
00459 uint32 ver = T::getVersion ();
00460 ofile.serial (nbEntries);
00461 ofile.serial (ver);
00462 ofile.serialCont(container);
00463 ofile.close ();
00464 }
00465 }
00466 catch (NLMISC::Exception &e)
00467 {
00468 nlinfo ("loadForm(): Exception during saving the packed file, it will be recreated next launch (%s)", e.what());
00469 }
00470
00471
00472 sheetIds.clear ();
00473 filenames.clear ();
00474 }
00475
00476
00482 template <class T>
00483 void loadForm (const std::string &sheetFilter, const std::string &packedFilename, std::map<NLMISC::CSheetId, T> &container, bool updatePackedSheet=true, bool errorIfPackedSheetNotGood=true)
00484 {
00485 std::vector<std::string> vs;
00486 vs.push_back(sheetFilter);
00487 loadForm(vs, packedFilename, container, updatePackedSheet, errorIfPackedSheetNotGood);
00488 }
00489
00490
00491
00492
00493 template <class T>
00494 void loadForm2(const std::vector<std::string> &sheetFilters, const std::string &packedFilename, std::map<NLMISC::CSheetId, NLMISC::CSmartPtr<T> > &container, bool updatePackedSheet=true, bool errorIfPackedSheetNotGood=true)
00495 {
00496 std::vector<std::string> dictionnary;
00497 std::map<std::string, uint> dictionnaryIndex;
00498 std::map<NLMISC::CSheetId, std::vector<uint32> > dependencies;
00499 std::vector<uint32> dependencyDates;
00500
00501
00502 nlassert (packedFilename.find (".packed_sheets") != std::string::npos);
00503
00504 std::string packedFilenamePath = NLMISC::CPath::lookup(NLMISC::CFile::getFilename(packedFilename), false, false);
00505 if (packedFilenamePath.empty())
00506 {
00507 packedFilenamePath = packedFilename;
00508 }
00509
00510
00511 NLMISC::CSheetId::init(updatePackedSheet);
00512
00513
00514 try
00515 {
00516 NLMISC::CIFile ifile;
00517 ifile.setCacheFileOnOpen(true);
00518 if (!ifile.open (packedFilenamePath))
00519 {
00520 throw NLMISC::Exception("can't open PackedSheet %s", packedFilenamePath.c_str());
00521 }
00522
00523
00524 nlinfo ("loadForm(): Loading packed file '%s'", packedFilename.c_str());
00525
00526
00527 ifile.serialCheck(PACKED_SHEET_HEADER);
00528 ifile.serialCheck(PACKED_SHEET_VERSION);
00529 sint loadFormVersion= ifile.serialVersion(PACKED_SHEET_VERSION_COMPATIBLE);
00530
00531
00532 uint32 dependBlockSize;
00533 ifile.serial(dependBlockSize);
00534
00535
00536 if(updatePackedSheet)
00537 {
00538
00539 {
00540 ifile.serialCont(dictionnary);
00541 }
00542
00543 {
00544 uint32 depSize;
00545 ifile.serial(depSize);
00546 for (uint i=0; i<depSize; ++i)
00547 {
00548 NLMISC::CSheetId sheetId;
00549
00550
00551 ifile.serial(sheetId);
00552 ifile.serialCont(dependencies[sheetId]);
00553 }
00554 }
00555 }
00556
00557 else if(dependBlockSize>0)
00558 {
00559 std::vector<uint8> bigBlock;
00560 bigBlock.resize(dependBlockSize);
00561 ifile.serialBuffer(&bigBlock[0], dependBlockSize);
00562 }
00563
00564
00565 uint32 nbEntries;
00566 uint32 ver;
00567 ifile.serial (nbEntries);
00568 ifile.serial (ver);
00569 if(ver != T::getVersion ())
00570 throw NLMISC::Exception("The packed sheet version in stream is different of the code");
00571 ifile.serialPtrCont (container);
00572 ifile.close ();
00573 }
00574 catch (NLMISC::Exception &e)
00575 {
00576
00577 container.clear ();
00578 if (!updatePackedSheet)
00579 {
00580 if (errorIfPackedSheetNotGood)
00581 nlerror ("loadForm(): Exception during reading the packed file and can't reconstruct them (%s)", e.what());
00582 else
00583 nlinfo ("loadForm(): Exception during reading the packed file and can't reconstruct them (%s)", e.what());
00584
00585 return;
00586 }
00587 else
00588 {
00589 nlinfo ("loadForm(): Exception during reading the packed file, I'll reconstruct it (%s)", e.what());
00590 }
00591 }
00592
00593
00594 if (!updatePackedSheet)
00595 {
00596 nlinfo ("Don't update the packed sheet with real sheet");
00597 return;
00598 }
00599
00600
00601 {
00602 for (uint i=0; i<dictionnary.size(); ++i)
00603 {
00604 std::string p = NLMISC::CPath::lookup (dictionnary[i], false, false);
00605 if (!p.empty())
00606 {
00607 uint32 d = NLMISC::CFile::getFileModificationDate(p);
00608 dependencyDates.push_back(d);
00609 }
00610 else
00611 {
00612
00613
00614 nldebug("Can't find dependent file %s !", dictionnary[i].c_str());
00615 dependencyDates.push_back(0xffffffff);
00616 }
00617 }
00618 }
00619
00620
00621 std::vector<NLMISC::CSheetId> sheetIds;
00622 std::vector<std::string> filenames;
00623 for (uint i = 0; i < sheetFilters.size(); i++)
00624 NLMISC::CSheetId::buildIdVector(sheetIds, filenames, sheetFilters[i]);
00625
00626
00627 if (sheetIds.empty())
00628 return;
00629
00630
00631 std::map<NLMISC::CSheetId, bool> sheetToRemove;
00632 for (typename std::map<NLMISC::CSheetId, NLMISC::CSmartPtr<T> >::iterator it = container.begin(); it != container.end(); it++)
00633 {
00634 sheetToRemove.insert (std::make_pair((*it).first, true));
00635 }
00636
00637
00638 uint32 packedFiledate = NLMISC::CFile::getFileModificationDate(packedFilenamePath);
00639
00640 bool containerChanged = false;
00641
00642 NLGEORGES::UFormLoader *formLoader = NULL;
00643
00644 std::vector<uint> NeededToRecompute;
00645
00646 for (uint k = 0; k < filenames.size(); k++)
00647 {
00648 std::string p = NLMISC::CPath::lookup (filenames[k], false, false);
00649 if (p.empty()) continue;
00650 uint32 d = NLMISC::CFile::getFileModificationDate(p);
00651
00652
00653 sheetToRemove[sheetIds[k]] = false;
00654
00655 if( d > packedFiledate || container.find (sheetIds[k]) == container.end())
00656 {
00657 NeededToRecompute.push_back(k);
00658 }
00659 else
00660 {
00661
00662 nlassert(dependencies.find(sheetIds[k]) != dependencies.end());
00663 std::vector<uint32> &depends = dependencies[sheetIds[k]];
00664
00665 for (uint i=0; i<depends.size(); ++i)
00666 {
00667 if (dependencyDates[depends[i]] > packedFiledate)
00668 {
00669 nldebug("Dependency on %s for %s not up to date !",
00670 dictionnary[depends[i]].c_str(), sheetIds[k].toString().c_str());
00671 NeededToRecompute.push_back(k);
00672 break;
00673 }
00674 }
00675 }
00676 }
00677
00678 nlinfo ("%d sheets checked, %d need to be recomputed", filenames.size(), NeededToRecompute.size());
00679
00680 NLMISC::TTime last = NLMISC::CTime::getLocalTime ();
00681 NLMISC::TTime start = NLMISC::CTime::getLocalTime ();
00682
00683 NLMISC::CSmartPtr<NLGEORGES::UForm> form;
00684 std::vector<NLMISC::CSmartPtr<NLGEORGES::UForm> > cacheFormList;
00685
00686 for (uint j = 0; j < NeededToRecompute.size(); j++)
00687 {
00688 if(NLMISC::CTime::getLocalTime () > last + 5000)
00689 {
00690 last = NLMISC::CTime::getLocalTime ();
00691 if(j>0)
00692 nlinfo ("%.0f%% completed (%d/%d), %d seconds remaining", (float)j*100.0/NeededToRecompute.size(),j,NeededToRecompute.size(), (NeededToRecompute.size()-j)*(last-start)/j/1000);
00693 }
00694
00695
00696 if (formLoader == NULL)
00697 {
00698 NLMISC::WarningLog->addNegativeFilter("CFormLoader: Can't open the form file");
00699 formLoader = NLGEORGES::UFormLoader::createLoader ();
00700 }
00701
00702
00703 if (form)
00704 cacheFormList.push_back (form);
00705
00706
00707 form = formLoader->loadForm (sheetIds[NeededToRecompute[j]].toString().c_str ());
00708 if (form)
00709 {
00710
00711 {
00712 std::vector<uint32> depends;
00713 std::set<std::string> dependFiles;
00714 form->getDependencies (dependFiles);
00715 nlassert(dependFiles.find(sheetIds[NeededToRecompute[j]].toString()) != dependFiles.end());
00716
00717 dependFiles.erase(sheetIds[NeededToRecompute[j]].toString());
00718
00719 std::set<std::string>::iterator first(dependFiles.begin()), last(dependFiles.end());
00720 for (; first != last; ++first)
00721 {
00722 const std::string filename = NLMISC::CFile::getFilename(*first);
00723 std::map<std::string,uint>::iterator findDicIt=dictionnaryIndex.find(filename);
00724
00725 if (findDicIt!=dictionnaryIndex.end())
00726 {
00727 depends.push_back(findDicIt->second);
00728 continue;
00729 }
00730
00731 std::string p = NLMISC::CPath::lookup (*first, false, false);
00732 if (!p.empty())
00733 {
00734 uint dicIndex;
00735
00736 dicIndex = dictionnary.size();
00737 dictionnaryIndex.insert(std::make_pair(filename, dictionnary.size()));
00738 dictionnary.push_back(filename);
00739
00740
00741 depends.push_back(dicIndex);
00742 }
00743 }
00744
00745 dependencies[sheetIds[NeededToRecompute[j]]] = depends;
00746 }
00747
00748
00749 typedef typename std::map<NLMISC::CSheetId, NLMISC::CSmartPtr<T> >::iterator TType1;
00750 typedef typename std::pair<TType1, bool> TType2;
00751 TType2 res = container.insert(std::make_pair(sheetIds[NeededToRecompute[j]], NLMISC::CSmartPtr<T>(new T())));
00752
00753 (*res.first).second->readGeorges (form, sheetIds[NeededToRecompute[j]]);
00754 containerChanged = true;
00755 }
00756 }
00757
00758 if(NeededToRecompute.size() > 0)
00759 nlinfo ("%d seconds to recompute %d sheets", (uint32)(NLMISC::CTime::getLocalTime()-start)/1000, NeededToRecompute.size());
00760
00761
00762 if (formLoader != NULL)
00763 {
00764 NLGEORGES::UFormLoader::releaseLoader (formLoader);
00765 NLMISC::WarningLog->removeFilter ("CFormLoader: Can't open the form file");
00766 }
00767
00768
00769 for (std::map<NLMISC::CSheetId, bool>::iterator it2 = sheetToRemove.begin(); it2 != sheetToRemove.end(); it2++)
00770 {
00771 if((*it2).second)
00772 {
00773 nlinfo ("the sheet '%s' is not in the directory, remove it from container", (*it2).first.toString().c_str());
00774 container.find((*it2).first)->second->removed();
00775 container.erase((*it2).first);
00776 containerChanged = true;
00777 dependencies.erase((*it2).first);
00778 }
00779 }
00780
00781
00782 try
00783 {
00784 if(containerChanged)
00785 {
00786 NLMISC::COFile ofile;
00787 ofile.open(packedFilenamePath);
00788
00789
00790 ofile.serialCheck(PACKED_SHEET_HEADER);
00791 ofile.serialCheck(PACKED_SHEET_VERSION);
00792 ofile.serialVersion(PACKED_SHEET_VERSION_COMPATIBLE);
00793
00794
00795 sint32 posBlockSize= ofile.getPos();
00796 uint32 dependBlockSize= 0;
00797 ofile.serial(dependBlockSize);
00798
00799
00800 ofile.serialCont(dictionnary);
00801
00802
00803 uint32 depSize = dependencies.size();
00804 ofile.serial(depSize);
00805 std::map<NLMISC::CSheetId, std::vector<uint32> >::iterator first(dependencies.begin()), last(dependencies.end());
00806 for (; first != last; ++first)
00807 {
00808 NLMISC::CSheetId si = first->first;
00809 ofile.serial(si);
00810 ofile.serialCont(first->second);
00811 }
00812
00813
00814 sint32 endBlockSize= ofile.getPos();
00815 dependBlockSize= (endBlockSize - posBlockSize) - 4;
00816 ofile.seek(posBlockSize, NLMISC::IStream::begin);
00817 ofile.serial(dependBlockSize);
00818 ofile.seek(endBlockSize, NLMISC::IStream::begin);
00819
00820
00821 uint32 nbEntries = sheetIds.size();
00822 uint32 ver = T::getVersion ();
00823 ofile.serial (nbEntries);
00824 ofile.serial (ver);
00825 ofile.serialPtrCont(container);
00826 ofile.close ();
00827 }
00828 }
00829 catch (NLMISC::Exception &e)
00830 {
00831 nlinfo ("loadForm(): Exception during saving the packed file, it will be recreated next launch (%s)", e.what());
00832 }
00833
00834
00835 sheetIds.clear ();
00836 filenames.clear ();
00837 }
00838
00839
00840
00841 template <class T>
00842 void loadForm2(const std::string &sheetFilter, const std::string &packedFilename, std::map<NLMISC::CSheetId, T> &container, bool updatePackedSheet=true, bool errorIfPackedSheetNotGood=true)
00843 {
00844 std::vector<std::string> vs;
00845 vs.push_back(sheetFilter);
00846 loadForm2(vs, packedFilename, container, updatePackedSheet, errorIfPackedSheetNotGood);
00847 }
00848
00849
00850
00851
00857 template <class T>
00858 void loadForm (const std::vector<std::string> &sheetFilters, const std::string &packedFilename, std::map<std::string, T> &container, bool updatePackedSheet=true, bool errorIfPackedSheetNotGood=true)
00859 {
00860 std::vector<std::string> dictionnary;
00861 std::map<std::string, uint> dictionnaryIndex;
00862 std::map<std::string, std::vector<uint32> > dependencies;
00863 std::vector<uint32> dependencyDates;
00864
00865
00866 nlassert (packedFilename.find (".packed_sheets") != std::string::npos);
00867
00868 std::string packedFilenamePath = NLMISC::CPath::lookup(packedFilename, false, false);
00869 if (packedFilenamePath.empty())
00870 {
00871 packedFilenamePath = packedFilename;
00872 }
00873
00874
00875
00876
00877
00878 try
00879 {
00880 NLMISC::CIFile ifile;
00881 ifile.setCacheFileOnOpen(true);
00882 ifile.open (packedFilenamePath);
00883
00884
00885 nlinfo ("loadForm(): Loading packed file '%s'", packedFilename.c_str());
00886
00887
00888 ifile.serialCheck(PACKED_SHEET_HEADER);
00889 ifile.serialCheck(PACKED_SHEET_VERSION);
00890 ifile.serialVersion(PACKED_SHEET_VERSION_COMPATIBLE);
00891
00892
00893 uint32 dependBlockSize;
00894 ifile.serial(dependBlockSize);
00895
00896
00897 if(updatePackedSheet)
00898 {
00899
00900 {
00901 ifile.serialCont(dictionnary);
00902 }
00903
00904 {
00905 uint32 depSize;
00906 ifile.serial(depSize);
00907 for (uint i=0; i<depSize; ++i)
00908 {
00909 std::string sheetName;
00910
00911
00912 ifile.serial(sheetName);
00913 ifile.serialCont(dependencies[sheetName]);
00914 }
00915 }
00916 }
00917
00918 else if(dependBlockSize>0)
00919 {
00920 std::vector<uint8> bigBlock;
00921 bigBlock.resize(dependBlockSize);
00922 ifile.serialBuffer(&bigBlock[0], dependBlockSize);
00923 }
00924
00925
00926 uint32 nbEntries;
00927 uint32 ver;
00928 ifile.serial (nbEntries);
00929 ifile.serial (ver);
00930 if(ver != T::getVersion ())
00931 throw NLMISC::Exception("The packed sheet version in stream is different of the code");
00932 ifile.serialCont (container);
00933 ifile.close ();
00934 }
00935 catch (NLMISC::Exception &e)
00936 {
00937
00938 container.clear ();
00939 if (!updatePackedSheet)
00940 {
00941 if (errorIfPackedSheetNotGood)
00942 nlerror ("loadForm(): Exception during reading the packed file and can't reconstruct them (%s)", e.what());
00943 else
00944 nlinfo ("loadForm(): Exception during reading the packed file and can't reconstruct them (%s)", e.what());
00945
00946 return;
00947 }
00948 else
00949 {
00950 nlinfo ("loadForm(): Exception during reading the packed file, I'll reconstruct it (%s)", e.what());
00951 }
00952 }
00953
00954
00955 if (!updatePackedSheet)
00956 {
00957 nlinfo ("Don't update the packed sheet with real sheet");
00958 return;
00959 }
00960
00961
00962 {
00963 for (uint i=0; i<dictionnary.size(); ++i)
00964 {
00965 std::string p = NLMISC::CPath::lookup (dictionnary[i], false, false);
00966 if (!p.empty())
00967 {
00968 uint32 d = NLMISC::CFile::getFileModificationDate(p);
00969 dependencyDates.push_back(d);
00970 }
00971 else
00972 {
00973
00974
00975 nldebug("Can't find dependent file %s !", dictionnary[i].c_str());
00976 dependencyDates.push_back(0xffffffff);
00977 }
00978 }
00979 }
00980
00981
00982 std::vector<std::string> sheetNames;
00983 {
00984 std::vector<std::string>::const_iterator first(sheetFilters.begin()), last(sheetFilters.end());
00985 for (; first != last; ++first)
00986 NLMISC::CPath::getFileList(*first, sheetNames);
00987
00988 }
00989
00990
00991 if (sheetNames.empty())
00992 return;
00993
00994
00995 std::map<std::string, bool> sheetToRemove;
00996 {
00997 typename std::map<std::string, T>::iterator first(container.begin()), last(container.end());
00998 for(; first != last; ++first)
00999 sheetToRemove.insert (make_pair(first->first, true));
01000 }
01001
01002
01003 uint32 packedFiledate = NLMISC::CFile::getFileModificationDate(packedFilenamePath);
01004
01005 bool containerChanged = false;
01006
01007 NLGEORGES::UFormLoader *formLoader = NULL;
01008
01009 std::vector<uint> NeededToRecompute;
01010
01011 for (uint k = 0; k < sheetNames.size(); k++)
01012 {
01013 std::string p = NLMISC::CPath::lookup (sheetNames[k], false, false);
01014 if (p.empty())
01015 {
01016 continue;
01017 }
01018 uint32 d = NLMISC::CFile::getFileModificationDate(p);
01019
01020
01021 sheetToRemove[sheetNames[k]] = false;
01022
01023 if( d > packedFiledate || container.find (sheetNames[k]) == container.end())
01024 {
01025 NeededToRecompute.push_back(k);
01026 }
01027 else
01028 {
01029
01030 nlassert(dependencies.find(sheetNames[k]) != dependencies.end());
01031 std::vector<uint32> &depends = dependencies[sheetNames[k]];
01032
01033 for (uint i=0; i<depends.size(); ++i)
01034 {
01035 if (dependencyDates[depends[i]] > packedFiledate)
01036 {
01037 nldebug("Dependancy on %s for %s not up to date !",
01038 dictionnary[depends[i]].c_str(), sheetNames[k].c_str());
01039 NeededToRecompute.push_back(k);
01040 break;
01041 }
01042 }
01043 }
01044 }
01045
01046 nlinfo ("%d sheets checked, %d need to be recomputed", sheetNames.size(), NeededToRecompute.size());
01047
01048 NLMISC::TTime lastTime = NLMISC::CTime::getLocalTime ();
01049 NLMISC::TTime start = NLMISC::CTime::getLocalTime ();
01050
01051 NLMISC::CSmartPtr<NLGEORGES::UForm> form;
01052
01053 for (uint j = 0; j < NeededToRecompute.size(); j++)
01054 {
01055 if(NLMISC::CTime::getLocalTime () > lastTime + 5000)
01056 {
01057 lastTime = NLMISC::CTime::getLocalTime ();
01058 if(j>0)
01059 nlinfo ("%.0f%% completed (%d/%d), %d seconds remaining", (float)j*100.0/NeededToRecompute.size(),j,NeededToRecompute.size(), (NeededToRecompute.size()-j)*(lastTime-start)/j/1000);
01060 }
01061
01062
01063 if (formLoader == NULL)
01064 {
01065 NLMISC::WarningLog->addNegativeFilter("CFormLoader: Can't open the form file");
01066 formLoader = NLGEORGES::UFormLoader::createLoader ();
01067 }
01068
01069
01070 form = formLoader->loadForm (sheetNames[NeededToRecompute[j]].c_str ());
01071 if (form)
01072 {
01073
01074 {
01075 std::vector<uint32> depends;
01076 std::set<std::string> dependFiles;
01077 form->getDependencies (dependFiles);
01078 nlassert(dependFiles.find(sheetNames[NeededToRecompute[j]]) != dependFiles.end());
01079
01080 dependFiles.erase(sheetNames[NeededToRecompute[j]]);
01081
01082 std::set<std::string>::iterator first(dependFiles.begin()), last(dependFiles.end());
01083 for (; first != last; ++first)
01084 {
01085 std::string p = NLMISC::CPath::lookup (*first, false, false);
01086 if (!p.empty())
01087 {
01088
01089
01090 uint dicIndex;
01091 std::string filename = NLMISC::CFile::getFilename(p);
01092
01093 if (dictionnaryIndex.find(filename) == dictionnaryIndex.end())
01094 {
01095
01096 dicIndex = dictionnary.size();
01097 dictionnaryIndex.insert(std::make_pair(filename, dictionnary.size()));
01098 dictionnary.push_back(filename);
01099 }
01100 else
01101 {
01102 dicIndex = dictionnaryIndex.find(filename)->second;
01103 }
01104
01105
01106 depends.push_back(dicIndex);
01107 }
01108 }
01109
01110 dependencies[sheetNames[NeededToRecompute[j]]] = depends;
01111 }
01112
01113
01114 typedef typename std::map<std::string, T>::iterator TType1;
01115 typedef typename std::pair<TType1, bool> TType2;
01116 TType2 res = container.insert(std::make_pair(sheetNames[NeededToRecompute[j]],T()));
01117
01118 (*res.first).second.readGeorges (form, sheetNames[NeededToRecompute[j]]);
01119 containerChanged = true;
01120 }
01121 }
01122
01123 nlinfo ("%d seconds to recompute %d sheets", (uint32)(NLMISC::CTime::getLocalTime()-start)/1000, NeededToRecompute.size());
01124
01125
01126 if (formLoader != NULL)
01127 {
01128 NLGEORGES::UFormLoader::releaseLoader (formLoader);
01129 NLMISC::WarningLog->removeFilter ("CFormLoader: Can't open the form file");
01130 }
01131
01132
01133 for (std::map<std::string, bool>::iterator it2 = sheetToRemove.begin(); it2 != sheetToRemove.end(); it2++)
01134 {
01135 if(it2->second)
01136 {
01137
01138 container.find(it2->first)->second.removed();
01139 container.erase(it2->first);
01140 containerChanged = true;
01141 dependencies.erase((*it2).first);
01142 }
01143 }
01144
01145
01146 try
01147 {
01148 if(containerChanged)
01149 {
01150 NLMISC::COFile ofile;
01151 ofile.open(packedFilenamePath);
01152
01153
01154 ofile.serialCheck(PACKED_SHEET_HEADER);
01155 ofile.serialCheck(PACKED_SHEET_VERSION);
01156 ofile.serialVersion(PACKED_SHEET_VERSION_COMPATIBLE);
01157
01158
01159 sint32 posBlockSize= ofile.getPos();
01160 uint32 dependBlockSize= 0;
01161 ofile.serial(dependBlockSize);
01162
01163
01164 ofile.serialCont(dictionnary);
01165
01166
01167 uint32 depSize = dependencies.size();
01168 ofile.serial(depSize);
01169 std::map<std::string, std::vector<uint32> >::iterator first(dependencies.begin()), last(dependencies.end());
01170 for (; first != last; ++first)
01171 {
01172 std::string sheetName = first->first;
01173 ofile.serial(sheetName);
01174 ofile.serialCont(first->second);
01175 }
01176
01177
01178 sint32 endBlockSize= ofile.getPos();
01179 dependBlockSize= (endBlockSize - posBlockSize) - 4;
01180 ofile.seek(posBlockSize, NLMISC::IStream::begin);
01181 ofile.serial(dependBlockSize);
01182 ofile.seek(endBlockSize, NLMISC::IStream::begin);
01183
01184
01185 uint32 nbEntries = sheetNames.size();
01186 uint32 ver = T::getVersion ();
01187 ofile.serial (nbEntries);
01188 ofile.serial (ver);
01189 ofile.serialCont(container);
01190 ofile.close ();
01191 }
01192 }
01193 catch (NLMISC::Exception &e)
01194 {
01195 nlinfo ("loadForm(): Exception during saving the packed file, it will be recreated next launch (%s)", e.what());
01196 }
01197
01198
01199 sheetNames.clear ();
01200 }
01201
01202
01208 template <class T>
01209 void loadForm (const std::string &sheetFilter, const std::string &packedFilename, std::map<std::string, T> &container, bool updatePackedSheet=true, bool errorIfPackedSheetNotGood=true)
01210 {
01211 std::vector<std::string> vs;
01212 vs.push_back(sheetFilter);
01213 loadForm(vs, packedFilename, container, updatePackedSheet, errorIfPackedSheetNotGood);
01214 }
01215
01216
01217 template <class T>
01218 void loadFormNoPackedSheet (const std::string &sheetFilter, std::map<NLMISC::CSheetId, T> &container, const std::string &wildcardFilter)
01219 {
01220 std::vector<std::string> vs;
01221 vs.push_back(sheetFilter);
01222 loadFormNoPackedSheet(vs, container, wildcardFilter);
01223 }
01224
01225
01226
01227 template <class T>
01228 void loadFormNoPackedSheet2 (const std::string &sheetFilter, std::map<NLMISC::CSheetId, T> &container, const std::string &wildcardFilter)
01229 {
01230 std::vector<std::string> vs;
01231 vs.push_back(sheetFilter);
01232 loadFormNoPackedSheet2(vs, container, wildcardFilter);
01233 }
01234
01235
01242 template <class T>
01243 void loadFormNoPackedSheet (const std::vector<std::string> &sheetFilters, std::map<NLMISC::CSheetId, T> &container, const std::string &wildcardFilter)
01244 {
01245
01246 NLMISC::CSheetId::init(false);
01247
01248
01249 std::vector<NLMISC::CSheetId> sheetIds;
01250 std::vector<std::string> filenames;
01251 for (uint i = 0; i < sheetFilters.size(); i++)
01252 NLMISC::CSheetId::buildIdVector(sheetIds, filenames, sheetFilters[i]);
01253
01254
01255
01256 if (sheetIds.empty())
01257 return;
01258
01259
01260
01261 std::vector<uint> NeededToRecompute;
01262 for (uint k = 0; k < filenames.size(); k++)
01263 {
01264 std::string p = NLMISC::CPath::lookup (filenames[k], false, false);
01265 if (p.empty()) continue;
01266
01267 if(!wildcardFilter.empty() && !NLMISC::testWildCard(p,wildcardFilter)) continue;
01268
01269 NeededToRecompute.push_back(k);
01270 }
01271 nlinfo ("%d sheets checked, %d need to be recomputed", filenames.size(), NeededToRecompute.size());
01272
01273
01274 NLMISC::TTime last = NLMISC::CTime::getLocalTime ();
01275 NLMISC::TTime start = NLMISC::CTime::getLocalTime ();
01276 NLGEORGES::UFormLoader *formLoader = NULL;
01277 NLMISC::CSmartPtr<NLGEORGES::UForm> form;
01278 std::vector<NLMISC::CSmartPtr<NLGEORGES::UForm> > cacheFormList;
01279
01280
01281 for (uint j = 0; j < NeededToRecompute.size(); j++)
01282 {
01283 if(NLMISC::CTime::getLocalTime () > last + 5000)
01284 {
01285 last = NLMISC::CTime::getLocalTime ();
01286 if(j>0)
01287 nlinfo ("%.0f%% completed (%d/%d), %d seconds remaining", (float)j*100.0/NeededToRecompute.size(),j,NeededToRecompute.size(), (NeededToRecompute.size()-j)*(last-start)/j/1000);
01288 }
01289
01290
01291 if (formLoader == NULL)
01292 {
01293 NLMISC::WarningLog->addNegativeFilter("CFormLoader: Can't open the form file");
01294 formLoader = NLGEORGES::UFormLoader::createLoader ();
01295 }
01296
01297
01298 if (form)
01299 cacheFormList.push_back (form);
01300
01301
01302 form = formLoader->loadForm (sheetIds[NeededToRecompute[j]].toString().c_str ());
01303 if (form)
01304 {
01305
01306 typedef typename std::map<NLMISC::CSheetId, T>::iterator TType1;
01307 typedef typename std::pair<TType1, bool> TType2;
01308 TType2 res = container.insert(std::make_pair(sheetIds[NeededToRecompute[j]],T()));
01309
01310 (*res.first).second.readGeorges (form, sheetIds[NeededToRecompute[j]]);
01311 }
01312 }
01313
01314 if(NeededToRecompute.size() > 0)
01315 nlinfo ("%d seconds to recompute %d sheets", (uint32)(NLMISC::CTime::getLocalTime()-start)/1000, NeededToRecompute.size());
01316
01317
01318 if (formLoader != NULL)
01319 {
01320 NLGEORGES::UFormLoader::releaseLoader (formLoader);
01321 NLMISC::WarningLog->removeFilter ("CFormLoader: Can't open the form file");
01322 }
01323
01324
01325 sheetIds.clear ();
01326 filenames.clear ();
01327 }
01328
01329
01330
01331 template <class T>
01332 void loadFormNoPackedSheet2 (const std::vector<std::string> &sheetFilters, std::map<NLMISC::CSheetId, NLMISC::CSmartPtr<T> > &container, const std::string &wildcardFilter)
01333 {
01334
01335 NLMISC::CSheetId::init(false);
01336
01337
01338 std::vector<NLMISC::CSheetId> sheetIds;
01339 std::vector<std::string> filenames;
01340 for (uint i = 0; i < sheetFilters.size(); i++)
01341 NLMISC::CSheetId::buildIdVector(sheetIds, filenames, sheetFilters[i]);
01342
01343
01344
01345 if (sheetIds.empty())
01346 return;
01347
01348
01349
01350 std::vector<uint> NeededToRecompute;
01351 for (uint k = 0; k < filenames.size(); k++)
01352 {
01353 std::string p = NLMISC::CPath::lookup (filenames[k], false, false);
01354 if (p.empty()) continue;
01355
01356 if(!wildcardFilter.empty() && !NLMISC::testWildCard(p,wildcardFilter)) continue;
01357
01358 NeededToRecompute.push_back(k);
01359 }
01360 nlinfo ("%d sheets checked, %d need to be recomputed", filenames.size(), NeededToRecompute.size());
01361
01362
01363 NLMISC::TTime last = NLMISC::CTime::getLocalTime ();
01364 NLMISC::TTime start = NLMISC::CTime::getLocalTime ();
01365 NLGEORGES::UFormLoader *formLoader = NULL;
01366 NLMISC::CSmartPtr<NLGEORGES::UForm> form;
01367 std::vector<NLMISC::CSmartPtr<NLGEORGES::UForm> > cacheFormList;
01368
01369
01370 for (uint j = 0; j < NeededToRecompute.size(); j++)
01371 {
01372 if(NLMISC::CTime::getLocalTime () > last + 5000)
01373 {
01374 last = NLMISC::CTime::getLocalTime ();
01375 if(j>0)
01376 nlinfo ("%.0f%% completed (%d/%d), %d seconds remaining", (float)j*100.0/NeededToRecompute.size(),j,NeededToRecompute.size(), (NeededToRecompute.size()-j)*(last-start)/j/1000);
01377 }
01378
01379
01380 if (formLoader == NULL)
01381 {
01382 NLMISC::WarningLog->addNegativeFilter("CFormLoader: Can't open the form file");
01383 formLoader = NLGEORGES::UFormLoader::createLoader ();
01384 }
01385
01386
01387 if (form)
01388 cacheFormList.push_back (form);
01389
01390
01391 form = formLoader->loadForm (sheetIds[NeededToRecompute[j]].toString().c_str ());
01392 if (form)
01393 {
01394
01395 typedef typename std::map<NLMISC::CSheetId, NLMISC::CSmartPtr<T> >::iterator TType1;
01396 typedef typename std::pair<TType1, bool> TType2;
01397 TType2 res = container.insert(std::make_pair(sheetIds[NeededToRecompute[j]], NLMISC::CSmartPtr<T>(new T())));
01398
01399 (*res.first).second->readGeorges (form, sheetIds[NeededToRecompute[j]]);
01400 }
01401 }
01402
01403 if(NeededToRecompute.size() > 0)
01404 nlinfo ("%d seconds to recompute %d sheets", (uint32)(NLMISC::CTime::getLocalTime()-start)/1000, NeededToRecompute.size());
01405
01406
01407 if (formLoader != NULL)
01408 {
01409 NLGEORGES::UFormLoader::releaseLoader (formLoader);
01410 NLMISC::WarningLog->removeFilter ("CFormLoader: Can't open the form file");
01411 }
01412
01413
01414 sheetIds.clear ();
01415 filenames.clear ();
01416 }
01417
01418 #endif // NL_LOAD_FORM_H
01419
01420