OpenClonk
C4UpdatePackage Class Reference

#include <C4Update.h>

Inheritance diagram for C4UpdatePackage:
[legend]
Collaboration diagram for C4UpdatePackage:
[legend]

Public Member Functions

bool Load (C4Group *pGroup)
 
bool Execute (C4Group *pGroup)
 
int Check (C4Group *pGroup)
 
bool MakeUpdate (const char *strFile1, const char *strFile2, const char *strUpdateFile, const char *strName=nullptr)
 
void CompileFunc (StdCompiler *pComp)
 
bool Load (C4Group &hGroup)
 
bool Save (C4Group &hGroup)
 

Static Public Member Functions

static bool Optimize (C4Group *pGrpFrom, const char *strTarget)
 

Public Attributes

int32_t RequireVersion [4] = { 0, 0, 0, 0 }
 
char Name [C4MaxName+1] = { 0 }
 
char DestPath [_MAX_PATH_LEN] = { 0 }
 
int32_t GrpUpdate = 0
 
int32_t UpGrpCnt = 0
 
uint32_t GrpChks1 [C4UP_MaxUpGrpCnt] = { 0 }
 
uint32_t GrpChks2 = 0
 

Protected Member Functions

bool DoUpdate (C4Group *pGrpFrom, class C4GroupEx *pGrpTo, const char *strFileName)
 
bool DoGrpUpdate (C4Group *pUpdateData, class C4GroupEx *pGrpTo)
 
bool MkUp (C4Group *pGrp1, C4Group *pGrp2, C4GroupEx *pUpGr, bool *fModified)
 
bool OpenUnpackParents (C4GroupEx &rGroup, const char *strGroup, const char *strEnsureMaker)
 
void WriteLog (const char *strMsg,...) GNUC_FORMAT_ATTRIBUTE_O
 

Static Protected Member Functions

static bool Optimize (C4Group *pGrpFrom, class C4GroupEx *pGrpTo, const char *strFileName)
 

Protected Attributes

CStdFile Log
 

Detailed Description

Definition at line 46 of file C4Update.h.

Member Function Documentation

◆ Check()

int C4UpdatePackage::Check ( C4Group pGroup)

Definition at line 431 of file C4Update.cpp.

432 {
433  // Version requirement is set
434  if (RequireVersion[0])
435  {
436  // Engine and game version must match (rest ignored)
437  if ((C4XVER1 != RequireVersion[0]) || (C4XVER2 != RequireVersion[1]))
438  return C4UPD_CHK_BAD_VERSION;
439  }
440 
441  // only group updates have any special needs
442  if (!GrpUpdate) return C4UPD_CHK_OK;
443 
444  // check source file
445  C4Group TargetGrp;
446  if (!TargetGrp.Open(DestPath))
447  return C4UPD_CHK_NO_SOURCE;
448  if (!TargetGrp.IsPacked())
449  return C4UPD_CHK_BAD_SOURCE;
450  TargetGrp.Close();
451 
452  // check source crc
453  uint32_t iCRC32;
454  if (!GetFileCRC(DestPath, &iCRC32))
455  return C4UPD_CHK_BAD_SOURCE;
456  // equal to destination group?
457  if (iCRC32 == GrpChks2)
458  // so there's nothing to do
460  // check if it's one of our registered sources
461  int i = 0;
462  for (; i < UpGrpCnt; i++)
463  if (iCRC32 == GrpChks1[i])
464  break;
465  if (i >= UpGrpCnt)
466  return C4UPD_CHK_BAD_SOURCE;
467 
468  // ok
469  return C4UPD_CHK_OK;
470 }
#define C4UPD_CHK_NO_SOURCE
Definition: C4Update.h:41
#define C4UPD_CHK_BAD_VERSION
Definition: C4Update.h:44
#define C4UPD_CHK_ALREADY_UPDATED
Definition: C4Update.h:43
#define C4UPD_CHK_OK
Definition: C4Update.h:40
#define C4UPD_CHK_BAD_SOURCE
Definition: C4Update.h:42
bool GetFileCRC(const char *szFilename, uint32_t *pCRC32)
Definition: CStdFile.cpp:355
bool IsPacked() const
Definition: C4Group.cpp:2541
bool Close()
Definition: C4Group.cpp:971
bool Open(const char *group_name, bool do_create=false)
Definition: C4Group.cpp:660
int32_t UpGrpCnt
Definition: C4Update.h:32
int32_t GrpUpdate
Definition: C4Update.h:31
int32_t RequireVersion[4]
Definition: C4Update.h:28
uint32_t GrpChks2
Definition: C4Update.h:33
char DestPath[_MAX_PATH_LEN]
Definition: C4Update.h:30
uint32_t GrpChks1[C4UP_MaxUpGrpCnt]
Definition: C4Update.h:33

References C4UPD_CHK_ALREADY_UPDATED, C4UPD_CHK_BAD_SOURCE, C4UPD_CHK_BAD_VERSION, C4UPD_CHK_NO_SOURCE, C4UPD_CHK_OK, C4Group::Close(), C4UpdatePackageCore::DestPath, GetFileCRC(), C4UpdatePackageCore::GrpChks1, C4UpdatePackageCore::GrpChks2, C4UpdatePackageCore::GrpUpdate, C4Group::IsPacked(), C4Group::Open(), C4UpdatePackageCore::RequireVersion, and C4UpdatePackageCore::UpGrpCnt.

Referenced by C4Group_ApplyUpdate().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ CompileFunc()

void C4UpdatePackageCore::CompileFunc ( StdCompiler pComp)
inherited

Definition at line 230 of file C4Update.cpp.

231 {
232  pComp->Value(mkNamingAdapt(toC4CArr(RequireVersion), "RequireVersion"));
233  pComp->Value(mkNamingAdapt(toC4CStr(Name), "Name", ""));
234  pComp->Value(mkNamingAdapt(toC4CStr(DestPath), "DestPath", ""));
235  pComp->Value(mkNamingAdapt(GrpUpdate, "GrpUpdate", 0));
236  pComp->Value(mkNamingAdapt(UpGrpCnt, "TargetCount", 0));
237  pComp->Value(mkNamingAdapt(toC4CArrU(GrpChks1), "GrpChks1"));
238  pComp->Value(mkNamingAdapt(GrpChks2, "GrpChks2", 0u));
239 }
#define toC4CArr(rArr)
Definition: StdAdaptors.h:28
#define toC4CArrU(rArr)
Definition: StdAdaptors.h:29
StdNamingAdapt< T > mkNamingAdapt(T &&rValue, const char *szName)
Definition: StdAdaptors.h:92
#define toC4CStr(szString)
Definition: StdAdaptors.h:24
char Name[C4MaxName+1]
Definition: C4Update.h:29
void Value(const T &rStruct)
Definition: StdCompiler.h:161

References C4UpdatePackageCore::DestPath, C4UpdatePackageCore::GrpChks1, C4UpdatePackageCore::GrpChks2, C4UpdatePackageCore::GrpUpdate, mkNamingAdapt(), C4UpdatePackageCore::Name, C4UpdatePackageCore::RequireVersion, toC4CArr, toC4CArrU, toC4CStr, C4UpdatePackageCore::UpGrpCnt, and StdCompiler::Value().

Here is the call graph for this function:

◆ DoGrpUpdate()

bool C4UpdatePackage::DoGrpUpdate ( C4Group pUpdateData,
class C4GroupEx pGrpTo 
)
protected

Definition at line 527 of file C4Update.cpp.

528 {
529  char *pData;
530  // sort entries
531  if (pUpdateData->LoadEntry(C4CFN_UpdateEntries, &pData, nullptr, 1))
532  {
533  // delete all entries that do not appear in the entries list
534  char strItemName[_MAX_FNAME_LEN], strItemName2[_MAX_FNAME_LEN];
535  pGrpTo->ResetSearch();
536  while (pGrpTo->FindNextEntry("*", strItemName))
537  {
538  bool fGotIt = false;
539  for (int i = 0; (fGotIt = SCopySegment(pData, i, strItemName2, '|', _MAX_FNAME)); i++)
540  {
541  // remove separator
542  char *pSep = strchr(strItemName2, '=');
543  if (pSep) *pSep = '\0';
544  // in list?
545  if (SEqual(strItemName, strItemName2))
546  break;
547  }
548  if (!fGotIt)
549  pGrpTo->DeleteEntry(strItemName);
550  }
551  // set entry times, set sort list
552  char strSortList[32767] = "";
553  for (int i = 0; SCopySegment(pData, i, strItemName, '|', _MAX_FNAME); i++)
554  {
555  // strip checksum/time (if given)
556  char *pTime = strchr(strItemName, '=');
557  if (pTime) *pTime = '\0';
558  // copy to sort list
559  SAppend(strItemName, strSortList);
560  SAppendChar('|', strSortList);
561  }
562  // sort by list
563  pGrpTo->Sort(strSortList);
564  delete[] pData;
565  }
566  // copy header from update group
567  pGrpTo->SetHead(*pUpdateData);
568  // ok
569  return true;
570 }
#define C4CFN_UpdateEntries
Definition: C4Components.h:51
#define _MAX_FNAME
#define _MAX_FNAME_LEN
bool SCopySegment(const char *szString, int iSegment, char *sTarget, char cSeparator, int iMaxL, bool fSkipWhitespace)
Definition: Standard.cpp:279
void SAppendChar(char cChar, char *szStr)
Definition: Standard.cpp:271
void SAppend(const char *szSource, char *szTarget, int iMaxL)
Definition: Standard.cpp:263
bool SEqual(const char *szStr1, const char *szStr2)
Definition: Standard.h:93
bool LoadEntry(const char *entry_name, char **buffer, size_t *size_info=nullptr, int zeros_to_append=0)
Definition: C4Group.cpp:2375

References _MAX_FNAME, _MAX_FNAME_LEN, C4CFN_UpdateEntries, C4Group::DeleteEntry(), C4Group::FindNextEntry(), C4Group::LoadEntry(), C4Group::ResetSearch(), SAppend(), SAppendChar(), SCopySegment(), SEqual(), C4GroupEx::SetHead(), and C4Group::Sort().

Referenced by DoUpdate(), and Execute().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ DoUpdate()

bool C4UpdatePackage::DoUpdate ( C4Group pGrpFrom,
class C4GroupEx pGrpTo,
const char *  strFileName 
)
protected

Definition at line 472 of file C4Update.cpp.

473 {
474  // group file?
475  C4Group ItemGroupFrom;
476  if (ItemGroupFrom.OpenAsChild(pGrpFrom, strFileName))
477  {
478  // try to open target group
479  C4GroupEx ItemGroupTo;
480  char strTempGroup[_MAX_PATH_LEN]; strTempGroup[0] = 0;
481  if (!ItemGroupTo.OpenAsChild(pGrpTo, strFileName, false, true))
482  return false;
483  // update children
484  char ItemFileName[_MAX_PATH];
485  ItemGroupFrom.ResetSearch();
486  while (ItemGroupFrom.FindNextEntry("*", ItemFileName))
487  if (!SEqual(ItemFileName, C4CFN_UpdateCore) && !SEqual(ItemFileName, C4CFN_UpdateEntries))
488  DoUpdate(&ItemGroupFrom, &ItemGroupTo, ItemFileName);
489  if (GrpUpdate)
490  {
491  DoGrpUpdate(&ItemGroupFrom, &ItemGroupTo);
492  // write group (do not change any headers set by DoGrpUpdate!)
493  ItemGroupTo.Close(false);
494  // set core (C4Group::Save overwrites it)
495  pGrpTo->SaveEntryCore(*pGrpFrom, strFileName);
496  pGrpTo->SetSavedEntryCore(strFileName);
497  // flag as no-resort
498  pGrpTo->SetNoSort(strFileName);
499  }
500  else
501  {
502  // write group
503  ItemGroupTo.Close(true);
504  // temporary group?
505  if (strTempGroup[0])
506  if (!pGrpTo->Move(strTempGroup, strFileName))
507  return false;
508  }
509  }
510  else
511  {
512 #ifdef _WIN32
513  OutputDebugString(FormatString("updating %s\\%s\n", pGrpTo->GetFullName().getData(), strFileName).GetWideChar());
514 #elif defined(_DEBUG)
515  printf("updating %s\\%s\n", pGrpTo->GetFullName().getData(), strFileName);
516 #endif
517  if (!C4Group_CopyEntry(pGrpFrom, pGrpTo, strFileName))
518  return false;
519  // set core
520  pGrpTo->SaveEntryCore(*pGrpFrom, strFileName);
521  pGrpTo->SetSavedEntryCore(strFileName);
522  }
523  // ok
524  return true;
525 }
#define C4CFN_UpdateCore
Definition: C4Components.h:50
bool C4Group_CopyEntry(C4Group *pFrom, C4Group *pTo, const char *strItemName)
Definition: C4Update.cpp:31
#define _MAX_PATH
#define _MAX_PATH_LEN
StdStrBuf FormatString(const char *szFmt,...)
Definition: StdBuf.cpp:270
bool Close(bool fHeaderUpdate)
Definition: C4Update.cpp:222
bool FindNextEntry(const char *wildcard, StdStrBuf *filename=nullptr, size_t *size=nullptr, bool start_at_filename=false)
Definition: C4Group.cpp:2217
bool OpenAsChild(C4Group *mother, const char *entry_name, bool is_exclusive=false, bool do_create=false)
Definition: C4Group.cpp:1952
void ResetSearch(bool reload_contents=false)
Definition: C4Group.cpp:1316
bool DoUpdate(C4Group *pGrpFrom, class C4GroupEx *pGrpTo, const char *strFileName)
Definition: C4Update.cpp:472
bool DoGrpUpdate(C4Group *pUpdateData, class C4GroupEx *pGrpTo)
Definition: C4Update.cpp:527

References _MAX_PATH, _MAX_PATH_LEN, C4CFN_UpdateCore, C4CFN_UpdateEntries, C4Group_CopyEntry(), C4GroupEx::Close(), DoGrpUpdate(), C4Group::FindNextEntry(), FormatString(), StdStrBuf::getData(), C4Group::GetFullName(), C4UpdatePackageCore::GrpUpdate, C4Group::Move(), C4Group::OpenAsChild(), C4Group::ResetSearch(), C4GroupEx::SaveEntryCore(), SEqual(), C4GroupEx::SetNoSort(), and C4GroupEx::SetSavedEntryCore().

Referenced by Execute().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Execute()

bool C4UpdatePackage::Execute ( C4Group pGroup)

Definition at line 303 of file C4Update.cpp.

304 {
305 
306  // search target
307  C4GroupEx TargetGrp;
308  char strTarget[_MAX_PATH]; SCopy(DestPath, strTarget, _MAX_PATH);
309  char *p = strTarget, *lp = strTarget;
310  while ((p = strchr(p + 1, '\\')))
311  {
312  *p = 0;
313  if (!*(p + 1)) break;
314  if (!SEqual(lp, ".."))
315  {
316  if (TargetGrp.Open(strTarget))
317  {
318  // packed?
319  bool fPacked = TargetGrp.IsPacked();
320  // Close Group
321  TargetGrp.Close(true);
322  if (fPacked)
323  // Unpack
324  C4Group_UnpackDirectory(strTarget);
325  }
326  else
327  {
328  // GrpUpdate -> file must exist
329  if (GrpUpdate) return false;
330  // create dir
331  CreatePath(strTarget);
332  }
333  }
334  *p = '\\'; lp = p + 1;
335  }
336 
337  // try to open it
338  if (!TargetGrp.Open(strTarget, !GrpUpdate))
339  return false;
340 
341  // check if the update is allowed
342  if (GrpUpdate)
343  {
344  // check checksum
345  uint32_t iCRC32;
346  if (!GetFileCRC(TargetGrp.GetFullName().getData(), &iCRC32))
347  return false;
348  int i = 0;
349  for (; i < UpGrpCnt; i++)
350  if (iCRC32 == GrpChks1[i])
351  break;
352  if (i >= UpGrpCnt)
353  return false;
354  }
355  else
356  {
357  // only allow Extra.ocg-Updates
358  if (!SEqual2(DestPath, "Extra.ocg"))
359  return false;
360  }
361 
362  // update children
363  char ItemFileName[_MAX_PATH];
364  pGroup->ResetSearch();
365  while (pGroup->FindNextEntry("*", ItemFileName))
366  if (!SEqual(ItemFileName, C4CFN_UpdateCore) && !SEqual(ItemFileName, C4CFN_UpdateEntries))
367  DoUpdate(pGroup, &TargetGrp, ItemFileName);
368 
369  // do GrpUpdate
370  if (GrpUpdate)
371  DoGrpUpdate(pGroup, &TargetGrp);
372 
373  // close the group
374  TargetGrp.Close(false);
375 
376  if (GrpUpdate)
377  {
378  // check the result
379  uint32_t iResChks;
380  if (!GetFileCRC(strTarget, &iResChks))
381  return false;
382  if (iResChks != GrpChks2)
383  {
384 #ifdef UPDATE_DEBUG
385  char *pData; int iSize;
386  CStdFile MyFile; MyFile.Load(strTarget, (BYTE **)&pData, &iSize, 0, true);
387  MyFile.Create("DiesesDingIstMist.txt", false);
388  MyFile.Write(pData, iSize);
389  MyFile.Close();
390 #endif
391  return false;
392  }
393  }
394 
395  return true;
396 }
bool C4Group_UnpackDirectory(const char *filename)
Definition: C4Group.cpp:401
uint8_t BYTE
bool SEqual2(const char *szStr1, const char *szStr2)
Definition: Standard.cpp:204
void SCopy(const char *szSource, char *sTarget, size_t iMaxL)
Definition: Standard.cpp:152
bool CreatePath(const std::string &path)
Definition: StdFile.cpp:656
int iSize
Definition: TstC4NetIO.cpp:32
StdStrBuf GetFullName() const
Definition: C4Group.cpp:2638
bool Close(StdBuf **ppMemory=nullptr)
Definition: CStdFile.cpp:151
bool Create(const char *szFileName, bool fCompressed=false, bool fExecutable=false, bool fMemory=false)
Definition: CStdFile.cpp:49
bool Write(const void *pBuffer, int iSize)
Definition: CStdFile.cpp:240
const char * getData() const
Definition: StdBuf.h:442

References _MAX_PATH, C4CFN_UpdateCore, C4CFN_UpdateEntries, C4Group_UnpackDirectory(), C4GroupEx::Close(), CStdFile::Close(), CStdFile::Create(), CreatePath(), C4UpdatePackageCore::DestPath, DoGrpUpdate(), DoUpdate(), C4Group::FindNextEntry(), StdStrBuf::getData(), GetFileCRC(), C4Group::GetFullName(), C4UpdatePackageCore::GrpChks1, C4UpdatePackageCore::GrpChks2, C4UpdatePackageCore::GrpUpdate, iSize, C4Group::IsPacked(), C4Group::Open(), C4Group::ResetSearch(), SCopy(), SEqual(), SEqual2(), C4UpdatePackageCore::UpGrpCnt, and CStdFile::Write().

Referenced by C4Group_ApplyUpdate().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Load() [1/2]

bool C4UpdatePackageCore::Load ( C4Group hGroup)
inherited

Definition at line 241 of file C4Update.cpp.

242 {
243  // Load from group
244  StdStrBuf Source;
245  if (!hGroup.LoadEntryString(C4CFN_UpdateCore,&Source))
246  return false;
247  try
248  {
249  // Compile data
250  CompileFromBuf<StdCompilerINIRead>(mkNamingAdapt(*this, "Update"), Source);
251  }
252  catch (StdCompiler::Exception *pExc)
253  {
254  delete pExc;
255  return false;
256  }
257  return true;
258 }
bool LoadEntryString(const char *entry_name, StdStrBuf *buffer)
Definition: C4Group.cpp:2430

References C4CFN_UpdateCore, C4Group::LoadEntryString(), and mkNamingAdapt().

Referenced by MakeUpdate().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Load() [2/2]

bool C4UpdatePackage::Load ( C4Group pGroup)

Definition at line 280 of file C4Update.cpp.

281 {
282  // read update core
283  StdStrBuf Source;
284  if (!pGroup->LoadEntryString(C4CFN_UpdateCore,&Source))
285  return false;
286  try
287  {
288  // Compile data
289  CompileFromBuf<StdCompilerINIRead>(mkNamingAdapt(*this, "Update"), Source);
290  }
291  catch (StdCompiler::Exception *pExc)
292  {
294  WriteLog("ERROR: %s (in %s)", pExc->Msg.getData(), Name.getData());
295  delete pExc;
296  return false;
297  }
298  return true;
299 }
#define DirSep
void WriteLog(const char *strMsg,...) GNUC_FORMAT_ATTRIBUTE_O
Definition: C4Update.cpp:825

References C4CFN_UpdateCore, DirSep, StdStrBuf::getData(), C4Group::GetFullName(), C4Group::LoadEntryString(), mkNamingAdapt(), StdCompiler::Exception::Msg, C4UpdatePackageCore::Name, and WriteLog().

Referenced by C4Group_ApplyUpdate().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ MakeUpdate()

bool C4UpdatePackage::MakeUpdate ( const char *  strFile1,
const char *  strFile2,
const char *  strUpdateFile,
const char *  strName = nullptr 
)

Definition at line 600 of file C4Update.cpp.

601 {
602 #ifdef UPDATE_DEBUG
603  char *pData; int iSize;
604  CStdFile MyFile; MyFile.Load(strFile2, (BYTE **)&pData, &iSize, 0, true);
605  MyFile.Create("SoIstRichtig.txt", false);
606  MyFile.Write(pData, iSize);
607  MyFile.Close();
608  MemScramble((BYTE *)pData, iSize);
609  MyFile.Create("UndSoAuch.txt", false);
610  MyFile.Write(pData, iSize);
611  MyFile.Close();
612 #endif
613 
614  // open Log
615  if (!Log.Create("Update.log"))
616  return false;
617 
618  // begin message
619  WriteLog("Source: %s\nTarget: %s\nOutput: %s\n\n", strFile1, strFile2, strUpdateFile);
620 
621  // open both groups
622  C4Group Group1, Group2;
623  if (!Group1.Open(strFile1)) { WriteLog("Error: could not open %s!\n", strFile1); return false; }
624  if (!Group2.Open(strFile2)) { WriteLog("Error: could not open %s!\n", strFile2); return false; }
625 
626  // All groups to be compared need to be packed
627  if (!Group1.IsPacked()) { WriteLog("Error: source group %s not packed!\n", strFile1); return false; }
628  if (!Group2.IsPacked()) { WriteLog("Error: target group %s not packed!\n", strFile2); return false; }
629  if (Group1.HasPackedMother()) { WriteLog("Error: source group %s must not have a packed mother group!\n", strFile1); return false; }
630  if (Group2.HasPackedMother()) { WriteLog("Error: target group %s must not have a packed mother group!\n", strFile2); return false; }
631 
632  // create/open update-group
633  C4GroupEx UpGroup;
634  if (!UpGroup.Open(strUpdateFile, true)) { WriteLog("Error: could not open %s!\n", strUpdateFile); return false; }
635 
636  // may be continued update-file -> try to load core
637  UpGrpCnt = 0;
638  bool fContinued = C4UpdatePackageCore::Load(UpGroup);
639 
640  // save crc2 for later check
641  unsigned int iOldChks2 = GrpChks2;
642 
643  // create core info
644  if (strName)
645  SCopy(strName, Name, C4MaxName);
646  else
647  sprintf(Name, "%s Update", GetFilename(strFile1));
648  SCopy(strFile1, DestPath, _MAX_PATH);
649  GrpUpdate = true;
650  if (!GetFileCRC(strFile1, &GrpChks1[UpGrpCnt]))
651  { WriteLog("Error: could not calc checksum for %s!\n", strFile1); return false; }
652  if (!GetFileCRC(strFile2, &GrpChks2))
653  { WriteLog("Error: could not calc checksum for %s!\n", strFile2); return false; }
654  if (fContinued)
655  {
656  // continuation check: GrpChks2 matches?
657  if (GrpChks2 != iOldChks2)
658  // that would mess up the update result...
659  { WriteLog("Error: could not add to update package - target groups don't match (checksum error)\n"); return false; }
660  // already supported by this update?
661  int i = 0;
662  for (; i < UpGrpCnt; i++)
663  if (GrpChks1[UpGrpCnt] == GrpChks1[i])
664  break;
665  if (i < UpGrpCnt)
666  { WriteLog("This update already supports the version of the source file.\n"); return false; }
667  }
668 
669  UpGrpCnt++;
670 
671  // save core
672  if (!C4UpdatePackageCore::Save(UpGroup))
673  { WriteLog("Could not save update package core!\n"); return false; }
674 
675  // compare groups, create update
676  bool fModified = false;
677  bool fSuccess = MkUp(&Group1, &Group2, &UpGroup, &fModified);
678  // close (save) it
679  UpGroup.Close(false);
680  // error?
681  if (!fSuccess)
682  {
683  WriteLog("Update package not created.\n");
684  EraseItem(strUpdateFile);
685  return false;
686  }
687 
688  WriteLog("Update package created.\n");
689  return true;
690 }
const unsigned int C4MaxName
void MemScramble(BYTE *, int)
Definition: C4Group.cpp:534
#define sprintf
Definition: Standard.h:162
bool EraseItem(const char *szItemName)
Definition: StdFile.cpp:833
char * GetFilename(char *szPath)
Definition: StdFile.cpp:42
bool HasPackedMother() const
Definition: C4Group.cpp:2543
bool Load(C4Group &hGroup)
Definition: C4Update.cpp:241
bool Save(C4Group &hGroup)
Definition: C4Update.cpp:260
CStdFile Log
Definition: C4Update.h:65
bool MkUp(C4Group *pGrp1, C4Group *pGrp2, C4GroupEx *pUpGr, bool *fModified)
Definition: C4Update.cpp:694

References _MAX_PATH, C4MaxName, C4GroupEx::Close(), CStdFile::Close(), CStdFile::Create(), C4UpdatePackageCore::DestPath, EraseItem(), GetFileCRC(), GetFilename(), C4UpdatePackageCore::GrpChks1, C4UpdatePackageCore::GrpChks2, C4UpdatePackageCore::GrpUpdate, C4Group::HasPackedMother(), iSize, C4Group::IsPacked(), C4UpdatePackageCore::Load(), Log, MemScramble(), MkUp(), C4UpdatePackageCore::Name, C4Group::Open(), C4UpdatePackageCore::Save(), SCopy(), sprintf, C4UpdatePackageCore::UpGrpCnt, CStdFile::Write(), and WriteLog().

Referenced by ProcessGroup().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ MkUp()

bool C4UpdatePackage::MkUp ( C4Group pGrp1,
C4Group pGrp2,
C4GroupEx pUpGr,
bool *  fModified 
)
protected

Definition at line 694 of file C4Update.cpp.

695 {
696  // (CAUTION: pGrp1 may be nullptr - that means that there is no counterpart for Grp2
697  // in the base group)
698 
699  // compare headers
700  if (!pGrp1 || pGrp1->EntryCRC32() != pGrp2->EntryCRC32())
701  *fModified = true;
702  // set header
703  pUpGrp->SetHead(*pGrp2);
704  // compare entries
705  char strItemName[_MAX_PATH], strItemName2[_MAX_PATH]; StdStrBuf EntryList;
706  strItemName[0] = strItemName2[0] = 0;
707  pGrp2->ResetSearch(); if (!*fModified) pGrp1->ResetSearch();
708  int iChangedEntries = 0;
709  while (pGrp2->FindNextEntry("*", strItemName, nullptr, !! strItemName[0]))
710  {
711  // add to entry list
712  if (!!EntryList) EntryList.AppendChar('|');
713  EntryList.AppendFormat("%s=%d", strItemName, pGrp2->EntryCRC32(strItemName));
714  // no modification detected yet? then check order
715  if (!*fModified)
716  {
717  if (!pGrp1->FindNextEntry("*", strItemName2, nullptr, !! strItemName2[0]))
718  *fModified = true;
719  else if (!SEqual(strItemName, strItemName2))
720  *fModified = true;
721  }
722 
723  // TODO: write DeleteEntries.txt
724 
725  // a child group?
726  C4GroupEx ChildGrp2;
727  if (ChildGrp2.OpenAsChild(pGrp2, strItemName))
728  {
729  // open in Grp1
730  C4Group *pChildGrp1 = new C4GroupEx();
731  if (!pGrp1 || !pChildGrp1->OpenAsChild(pGrp1, strItemName))
732  { delete pChildGrp1; pChildGrp1 = nullptr; }
733  // open group for update data
734  C4GroupEx UpdGroup; char strTempGroupName[_MAX_FNAME_LEN];
735  strTempGroupName[0] = 0;
736  if (!UpdGroup.OpenAsChild(pUpGrp, strItemName))
737  {
738  // create new group (may be temporary)
739  if (C4Group_TempPath[0]) { SCopy(C4Group_TempPath,strTempGroupName,_MAX_FNAME); SAppend("~upd",strTempGroupName,_MAX_FNAME); }
740  else SCopy("~upd",strTempGroupName,_MAX_FNAME);
741  MakeTempFilename(strTempGroupName);
742  if (!UpdGroup.Open(strTempGroupName, true)) { delete pChildGrp1; WriteLog("Error: could not create temp group\n"); return false; }
743  }
744  // do nested MkUp-search
745  bool Modified = false;
746  bool fSuccess = MkUp(pChildGrp1, &ChildGrp2, &UpdGroup, &Modified);
747  // sort & close
748  extern const char ** C4Group_SortList;
749  UpdGroup.SortByList(C4Group_SortList, ChildGrp2.GetName());
750  UpdGroup.Close(false);
751  // check entry crcs
752  if (!pGrp1 || (pGrp1->EntryCRC32(strItemName) != pGrp2->EntryCRC32(strItemName)))
753  Modified = true;
754  // add group (if modified)
755  if (fSuccess && Modified)
756  {
757  if (strTempGroupName[0])
758  if (!pUpGrp->Move(strTempGroupName, strItemName))
759  {
760  WriteLog("Error: could not add modified group\n");
761  return false;
762  }
763  // copy core
764  pUpGrp->SaveEntryCore(*pGrp2, strItemName);
765  pUpGrp->SetSavedEntryCore(strItemName);
766  // got a modification in a subgroup
767  *fModified = true;
768  iChangedEntries++;
769  }
770  else
771  // delete group (do not remove groups that existed before!)
772  if (strTempGroupName[0])
773  if (!EraseItem(strTempGroupName))
774  { WriteLog("Error: could not delete temporary directory\n"); return false; }
775  delete pChildGrp1;
776  }
777  else
778  {
779  // compare them (size & crc32)
780  if (!pGrp1 ||
781  pGrp1->EntrySize(strItemName) != pGrp2->EntrySize(strItemName) ||
782  pGrp1->EntryCRC32(strItemName) != pGrp2->EntryCRC32(strItemName))
783  {
784  bool fCopied = false;
785 
786  // save core (EntryCRC32 might set additional fields)
787  pUpGrp->SaveEntryCore(*pGrp2, strItemName);
788 
789  // already in update grp?
790  if (pUpGrp->EntrySize(strItemName) != pGrp2->EntrySize(strItemName) ||
791  pUpGrp->EntryCRC32(strItemName) != pGrp2->EntryCRC32(strItemName))
792  {
793  // copy it
794  if (!C4Group_CopyEntry(pGrp2, pUpGrp, strItemName))
795  {
796  WriteLog("Error: could not add changed entry to update group\n");
797  return false;
798  }
799  // set entry core
800  pUpGrp->SetSavedEntryCore(strItemName);
801  // modified...
802  *fModified = true;
803  fCopied = true;
804  }
805  iChangedEntries++;
806 
807  WriteLog("%s\\%s: update%s\n", pGrp2->GetFullName().getData(), strItemName, fCopied ? "" : " (already in group)");
808  }
809  }
810  }
811  // write entries list (always)
812  if (!pUpGrp->Add(C4CFN_UpdateEntries, EntryList, false, true))
813  {
814  WriteLog("Error: could not save entry list!");
815  return false;
816  }
817 
818  if (iChangedEntries > 0)
819  WriteLog("%s: %d/%d changed (%s)\n", pGrp2->GetFullName().getData(), iChangedEntries, pGrp2->EntryCount(), *fModified ? "update" : "skip");
820 
821  // success
822  return true;
823 }
const char ** C4Group_SortList
Definition: C4Group.cpp:61
char C4Group_TempPath[_MAX_PATH_LEN]
Definition: C4Group.cpp:59
void MakeTempFilename(char *szFilename)
Definition: StdFile.cpp:320
size_t EntrySize(const char *wildcard=nullptr)
Definition: C4Group.cpp:2333
const char * GetName() const
Definition: C4Group.cpp:2309
int EntryCount(const char *wildcard=nullptr)
Definition: C4Group.cpp:2314
unsigned int EntryCRC32(const char *wildcard=nullptr)
Definition: C4Group.cpp:2354
bool SortByList(const char **list, const char *filename=nullptr)
Definition: C4Group.cpp:2566
void AppendFormat(const char *szFmt,...) GNUC_FORMAT_ATTRIBUTE_O
Definition: StdBuf.cpp:190
void AppendChar(char cChar)
Definition: StdBuf.h:588

References _MAX_FNAME, _MAX_FNAME_LEN, _MAX_PATH, C4Group::Add(), StdStrBuf::AppendChar(), StdStrBuf::AppendFormat(), C4CFN_UpdateEntries, C4Group_CopyEntry(), C4Group_SortList, C4Group_TempPath, C4GroupEx::Close(), C4Group::EntryCount(), C4Group::EntryCRC32(), C4Group::EntrySize(), EraseItem(), C4Group::FindNextEntry(), StdStrBuf::getData(), C4Group::GetFullName(), C4Group::GetName(), MakeTempFilename(), C4Group::Move(), C4Group::Open(), C4Group::OpenAsChild(), C4Group::ResetSearch(), SAppend(), C4GroupEx::SaveEntryCore(), SCopy(), SEqual(), C4GroupEx::SetHead(), C4GroupEx::SetSavedEntryCore(), C4Group::SortByList(), and WriteLog().

Referenced by MakeUpdate().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ OpenUnpackParents()

bool C4UpdatePackage::OpenUnpackParents ( C4GroupEx rGroup,
const char *  strGroup,
const char *  strEnsureMaker 
)
protected

◆ Optimize() [1/2]

bool C4UpdatePackage::Optimize ( C4Group pGrpFrom,
class C4GroupEx pGrpTo,
const char *  strFileName 
)
staticprotected

Definition at line 572 of file C4Update.cpp.

573 {
574  // group file?
575  C4Group ItemGroupFrom;
576  if (!ItemGroupFrom.OpenAsChild(pGrpFrom, strFileName))
577  return true;
578  // try to open target group
579  C4GroupEx ItemGroupTo;
580  if (!ItemGroupTo.OpenAsChild(pGrpTo, strFileName))
581  return true;
582  // update children
583  char ItemFileName[_MAX_PATH];
584  ItemGroupFrom.ResetSearch();
585  while (ItemGroupFrom.FindNextEntry("*", ItemFileName))
586  Optimize(&ItemGroupFrom, &ItemGroupTo, ItemFileName);
587  // set head
588  if (ItemGroupTo.HeadIdentical(ItemGroupFrom, true))
589  ItemGroupTo.SetHead(ItemGroupFrom);
590  // write group (do not change any headers set by DoGrpUpdate!)
591  ItemGroupTo.Close(false);
592  // set core (C4Group::Save overwrites it)
593  pGrpTo->SaveEntryCore(*pGrpFrom, strFileName);
594  pGrpTo->SetSavedEntryCore(strFileName);
595  return true;
596 }
void SetHead(C4Group &rByGrp)
Definition: C4Update.cpp:172
bool HeadIdentical(C4Group &rByGrp, bool fLax)
Definition: C4Update.cpp:184
static bool Optimize(C4Group *pGrpFrom, const char *strTarget)
Definition: C4Update.cpp:398

References _MAX_PATH, C4GroupEx::Close(), C4Group::FindNextEntry(), C4GroupEx::HeadIdentical(), C4Group::OpenAsChild(), Optimize(), C4Group::ResetSearch(), C4GroupEx::SaveEntryCore(), C4GroupEx::SetHead(), and C4GroupEx::SetSavedEntryCore().

Here is the call graph for this function:

◆ Optimize() [2/2]

bool C4UpdatePackage::Optimize ( C4Group pGrpFrom,
const char *  strTarget 
)
static

Definition at line 398 of file C4Update.cpp.

399 {
400 
401  // Open target group
402  C4GroupEx TargetGrp;
403  if (!TargetGrp.Open(strTarget))
404  return false;
405 
406  // Both groups must be packed
407  if (!pGroup->IsPacked() || !TargetGrp.IsPacked())
408  {
409  TargetGrp.Close(false);
410  return false;
411  }
412 
413  // update children
414  char ItemFileName[_MAX_PATH];
415  pGroup->ResetSearch();
416  while (pGroup->FindNextEntry("*", ItemFileName))
417  if (!SEqual(ItemFileName, C4CFN_UpdateCore) && !SEqual(ItemFileName, C4CFN_UpdateEntries))
418  Optimize(pGroup, &TargetGrp, ItemFileName);
419 
420  // set header
421  if (TargetGrp.HeadIdentical(*pGroup, true))
422  TargetGrp.SetHead(*pGroup);
423 
424  // save
425  TargetGrp.Close(false);
426 
427  // okay
428  return true;
429 }

References _MAX_PATH, C4CFN_UpdateCore, C4CFN_UpdateEntries, C4GroupEx::Close(), C4Group::FindNextEntry(), C4GroupEx::HeadIdentical(), C4Group::IsPacked(), C4Group::Open(), C4Group::ResetSearch(), SEqual(), and C4GroupEx::SetHead().

Referenced by Optimize().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Save()

bool C4UpdatePackageCore::Save ( C4Group hGroup)
inherited

Definition at line 260 of file C4Update.cpp.

261 {
262  try
263  {
264  // decompile data
265  StdStrBuf Core = DecompileToBuf<StdCompilerINIWrite>(mkNamingAdapt(*this, "Update"));
266  char *stupid_buffer = new char[Core.getLength() + 1];
267  memcpy(stupid_buffer, Core.getMData(), Core.getLength() + 1);
268  // add to group
269  return hGroup.Add(C4CFN_UpdateCore, stupid_buffer, Core.getLength(), false, true);
270  }
271  catch (StdCompiler::Exception * pExc)
272  {
273  delete pExc;
274  return false;
275  }
276 }
bool Add(const char *filename, const char *entry_name)
Definition: C4Group.cpp:1621
char * getMData()
Definition: StdBuf.h:443
size_t getLength() const
Definition: StdBuf.h:445

References C4Group::Add(), C4CFN_UpdateCore, StdStrBuf::getLength(), StdStrBuf::getMData(), and mkNamingAdapt().

Referenced by MakeUpdate().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ WriteLog()

void C4UpdatePackage::WriteLog ( const char *  strMsg,
  ... 
)
protected

Definition at line 825 of file C4Update.cpp.

826 {
827  va_list arglist; va_start(arglist, strMsg);
828  char strOutp[1024];
829  vsprintf(strOutp, strMsg, arglist);
830  Log.Write(strOutp, strlen(strOutp));
831  Log.Flush();
832  ::Log(strOutp);
833 }
bool Flush()
Definition: CStdFile.h:70

References CStdFile::Flush(), Log, and CStdFile::Write().

Referenced by Load(), MakeUpdate(), and MkUp().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ DestPath

char C4UpdatePackageCore::DestPath[_MAX_PATH_LEN] = { 0 }
inherited

◆ GrpChks1

uint32_t C4UpdatePackageCore::GrpChks1[C4UP_MaxUpGrpCnt] = { 0 }
inherited

Definition at line 33 of file C4Update.h.

Referenced by Check(), C4UpdatePackageCore::CompileFunc(), Execute(), and MakeUpdate().

◆ GrpChks2

uint32_t C4UpdatePackageCore::GrpChks2 = 0
inherited

Definition at line 33 of file C4Update.h.

Referenced by Check(), C4UpdatePackageCore::CompileFunc(), Execute(), and MakeUpdate().

◆ GrpUpdate

int32_t C4UpdatePackageCore::GrpUpdate = 0
inherited

Definition at line 31 of file C4Update.h.

Referenced by Check(), C4UpdatePackageCore::CompileFunc(), DoUpdate(), Execute(), and MakeUpdate().

◆ Log

CStdFile C4UpdatePackage::Log
protected

Definition at line 65 of file C4Update.h.

Referenced by MakeUpdate(), and WriteLog().

◆ Name

char C4UpdatePackageCore::Name[C4MaxName+1] = { 0 }
inherited

Definition at line 29 of file C4Update.h.

Referenced by C4Group_ApplyUpdate(), C4UpdatePackageCore::CompileFunc(), Load(), and MakeUpdate().

◆ RequireVersion

int32_t C4UpdatePackageCore::RequireVersion[4] = { 0, 0, 0, 0 }
inherited

Definition at line 28 of file C4Update.h.

Referenced by C4Group_ApplyUpdate(), Check(), and C4UpdatePackageCore::CompileFunc().

◆ UpGrpCnt

int32_t C4UpdatePackageCore::UpGrpCnt = 0
inherited

Definition at line 32 of file C4Update.h.

Referenced by Check(), C4UpdatePackageCore::CompileFunc(), Execute(), and MakeUpdate().


The documentation for this class was generated from the following files: