Skip to content

Commit

Permalink
C4Update: Add AllowMissingTarget option to AutoUpdate.txt (#127)
Browse files Browse the repository at this point in the history
* c4group: Add AllowMissingTarget to AutoUpdate.txt and expose it in c4group to allow update groups to work even if the target is missing
---------

Co-authored-by: George Tokmaji <[email protected]>
  • Loading branch information
maxmitti and Fulgen301 authored Oct 13, 2024
1 parent 7268090 commit 30ba2e1
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 39 deletions.
98 changes: 63 additions & 35 deletions src/C4Update.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ void C4UpdatePackageCore::CompileFunc(StdCompiler *pComp)
pComp->Value(mkNamingAdapt(toC4CStr(DestPath), "DestPath", ""));
pComp->Value(mkNamingAdapt(GrpUpdate, "GrpUpdate", 0));
pComp->Value(mkNamingAdapt(UpGrpCnt, "TargetCount", 0));
pComp->Value(mkNamingAdapt(AllowMissingTarget, "AllowMissingTarget", false));
pComp->Value(mkNamingAdapt(mkArrayAdapt(GrpChks1, 0u), "GrpChks1"));
pComp->Value(mkNamingAdapt(GrpChks2, "GrpChks2", 0u));
pComp->Value(mkNamingAdapt(mkArrayAdapt(GrpContentsCRC1, 0u), "GrpContentsCRC1"));
Expand Down Expand Up @@ -325,31 +326,44 @@ bool C4UpdatePackage::Execute(C4Group *pGroup)
}

// try to open it
bool targetMissing{false};
if (!TargetGrp.Open(strTarget, !GrpUpdate))
return false;
{
if (AllowMissingTarget && !ItemExists(strTarget) && TargetGrp.Open(strTarget, true))
{
targetMissing = true;
}
else
{
return false;
}
}

// check if the update is allowed
if (GrpUpdate)
{
// check checksum
uint32_t iContentsCRC32;
if (!C4Group_GetFileContentsCRC(TargetGrp.GetFullName().getData(), &iContentsCRC32))
return false;
int i = 0;
for (; i < UpGrpCnt; i++)
if (GrpContentsCRC1[i] && iContentsCRC32 == GrpContentsCRC1[i])
break;
if (i >= UpGrpCnt)
if (!targetMissing)
{
uint32_t iCRC32;
if (!C4Group_GetFileCRC(TargetGrp.GetFullName().getData(), &iCRC32))
// check checksum
uint32_t iContentsCRC32;
if (!C4Group_GetFileContentsCRC(TargetGrp.GetFullName().getData(), &iContentsCRC32))
return false;
int i = 0;
for (; i < UpGrpCnt; i++)
if (iCRC32 == GrpChks1[i])
if (GrpContentsCRC1[i] && iContentsCRC32 == GrpContentsCRC1[i])
break;
if (i >= UpGrpCnt)
return false;
{
uint32_t iCRC32;
if (!C4Group_GetFileCRC(TargetGrp.GetFullName().getData(), &iCRC32))
return false;
int i = 0;
for (; i < UpGrpCnt; i++)
if (iCRC32 == GrpChks1[i])
break;
if (i >= UpGrpCnt)
return false;
}
}
}
else
Expand Down Expand Up @@ -438,7 +452,17 @@ C4UpdatePackage::CheckResult C4UpdatePackage::Check(C4Group *pGroup)
// check source file
C4Group TargetGrp;
if (!TargetGrp.Open(DestPath))
return CheckResult::NoSource;
{
// make sure corrupted target files aren't overwritten
if (AllowMissingTarget && !ItemExists(DestPath))
{
return CheckResult::Ok;
}
else
{
return CheckResult::NoSource;
}
}
if (!TargetGrp.IsPacked())
return CheckResult::BadSource;
TargetGrp.Close();
Expand Down Expand Up @@ -624,7 +648,7 @@ bool C4UpdatePackage::Optimize(C4Group *pGrpFrom, C4GroupEx *pGrpTo, const char
return true;
}

bool C4UpdatePackage::MakeUpdate(const char *strFile1, const char *strFile2, const char *strUpdateFile, const char *strName)
bool C4UpdatePackage::MakeUpdate(const char *strFile1, const char *strFile2, const char *strUpdateFile, const char *strName, const bool allowMissingTarget)
{
// open Log
if (!Log.Create("Update.log"))
Expand Down Expand Up @@ -699,6 +723,7 @@ bool C4UpdatePackage::MakeUpdate(const char *strFile1, const char *strFile2, con
}

UpGrpCnt++;
AllowMissingTarget = allowMissingTarget;

// save core
if (!C4UpdatePackageCore::Save(UpGroup))
Expand All @@ -707,8 +732,8 @@ bool C4UpdatePackage::MakeUpdate(const char *strFile1, const char *strFile2, con
}

// compare groups, create update
bool fModified = false;
bool fSuccess = MkUp(&Group1, &Group2, &UpGroup, &fModified);
bool includeInUpdate{false};
bool fSuccess = MkUp(&Group1, &Group2, &UpGroup, includeInUpdate);
// close (save) it
UpGroup.Close(false);
// error?
Expand All @@ -723,7 +748,7 @@ bool C4UpdatePackage::MakeUpdate(const char *strFile1, const char *strFile2, con
return true;
}

bool C4UpdatePackage::MkUp(C4Group *pGrp1, C4Group *pGrp2, C4GroupEx *pUpGrp, bool *fModified)
bool C4UpdatePackage::MkUp(C4Group *pGrp1, C4Group *pGrp2, C4GroupEx *pUpGrp, bool &includeInUpdate)
{
// (CAUTION: pGrp1 may be nullptr - that means that there is no counterpart for Grp2
// in the base group)
Expand All @@ -734,27 +759,27 @@ bool C4UpdatePackage::MkUp(C4Group *pGrp1, C4Group *pGrp2, C4GroupEx *pUpGrp, bo
pGrp1->GetOriginal() != pGrp2->GetOriginal() ||
!SEqual(pGrp1->GetMaker(), pGrp2->GetMaker()) ||
!SEqual(pGrp1->GetPassword(), pGrp2->GetPassword()))
*fModified = true;
includeInUpdate = true;
// set header
pUpGrp->SetHead(*pGrp2);
// compare entries
char strItemName[_MAX_PATH], strItemName2[_MAX_PATH];
std::string entryList;
strItemName[0] = strItemName2[0] = 0;
pGrp2->ResetSearch(); if (!*fModified) pGrp1->ResetSearch();
pGrp2->ResetSearch(); if (!includeInUpdate) pGrp1->ResetSearch();
int iChangedEntries = 0;
while (pGrp2->FindNextEntry("*", strItemName, nullptr, nullptr, !!strItemName[0]))
{
// add to entry list
if (!entryList.empty()) entryList += '|';
entryList += std::format("{}={}", strItemName, pGrp2->EntryTime(strItemName));
// no modification detected yet? then check order
if (!*fModified)
if (!AllowMissingTarget && !includeInUpdate)
{
if (!pGrp1->FindNextEntry("*", strItemName2, nullptr, nullptr, !!strItemName2[0]))
*fModified = true;
includeInUpdate = true;
else if (!SEqual(strItemName, strItemName2))
*fModified = true;
includeInUpdate = true;
}

// TODO: write DeleteEntries.txt
Expand All @@ -780,17 +805,18 @@ bool C4UpdatePackage::MkUp(C4Group *pGrp1, C4Group *pGrp2, C4GroupEx *pUpGrp, bo
if (!UpdGroup.Open(strTempGroupName, true)) { delete pChildGrp1; WriteLog("Error: could not create temp group\n"); return false; }
}
// do nested MkUp-search
bool Modified = false;
bool fSuccess = MkUp(pChildGrp1, &ChildGrp2, &UpdGroup, &Modified);
bool childIncludeInUpdate{false};
bool fSuccess = MkUp(pChildGrp1, &ChildGrp2, &UpdGroup, childIncludeInUpdate);
// sort & close
extern const char **C4Group_SortList;
UpdGroup.SortByList(C4Group_SortList, ChildGrp2.GetName());
UpdGroup.Close(false);
// check entry times
if (!pGrp1 || (pGrp1->EntryTime(strItemName) != pGrp2->EntryTime(strItemName)))
Modified = true;
// always add the entire group if missing targets are allowed
// otherwise check entry times
if (AllowMissingTarget || !pGrp1 || (pGrp1->EntryTime(strItemName) != pGrp2->EntryTime(strItemName)))
childIncludeInUpdate = true;
// add group (if modified)
if (fSuccess && Modified)
if (fSuccess && childIncludeInUpdate)
{
if (strTempGroupName[0])
if (!pUpGrp->Move(strTempGroupName, strItemName))
Expand All @@ -802,7 +828,7 @@ bool C4UpdatePackage::MkUp(C4Group *pGrp1, C4Group *pGrp2, C4GroupEx *pUpGrp, bo
pUpGrp->SaveEntryCore(*pGrp2, strItemName);
pUpGrp->SetSavedEntryCore(strItemName);
// got a modification in a subgroup
*fModified = true;
includeInUpdate = true;
iChangedEntries++;
}
else
Expand All @@ -818,7 +844,8 @@ bool C4UpdatePackage::MkUp(C4Group *pGrp1, C4Group *pGrp2, C4GroupEx *pUpGrp, bo
else
{
// compare them (size & crc32)
if (!pGrp1 ||
if (AllowMissingTarget ||
!pGrp1 ||
pGrp1->EntrySize(strItemName) != pGrp2->EntrySize(strItemName) ||
pGrp1->EntryCRC32(strItemName) != pGrp2->EntryCRC32(strItemName))
{
Expand All @@ -828,7 +855,8 @@ bool C4UpdatePackage::MkUp(C4Group *pGrp1, C4Group *pGrp2, C4GroupEx *pUpGrp, bo
pUpGrp->SaveEntryCore(*pGrp2, strItemName);

// already in update grp?
if (pUpGrp->EntryTime(strItemName) != pGrp2->EntryTime(strItemName) ||
if (AllowMissingTarget ||
pUpGrp->EntryTime(strItemName) != pGrp2->EntryTime(strItemName) ||
pUpGrp->EntrySize(strItemName) != pGrp2->EntrySize(strItemName) ||
pUpGrp->EntryCRC32(strItemName) != pGrp2->EntryCRC32(strItemName))
{
Expand All @@ -841,7 +869,7 @@ bool C4UpdatePackage::MkUp(C4Group *pGrp1, C4Group *pGrp2, C4GroupEx *pUpGrp, bo
// set entry core
pUpGrp->SetSavedEntryCore(strItemName);
// modified...
*fModified = true;
includeInUpdate = true;
fCopied = true;
}
iChangedEntries++;
Expand All @@ -859,7 +887,7 @@ bool C4UpdatePackage::MkUp(C4Group *pGrp1, C4Group *pGrp2, C4GroupEx *pUpGrp, bo
}

if (iChangedEntries > 0)
WriteLog("{}: {}/{} changed ({})\n", pGrp2->GetFullName().getData(), iChangedEntries, pGrp2->EntryCount(), *fModified ? "update" : "skip");
WriteLog("{}: {}/{} changed ({})\n", pGrp2->GetFullName().getData(), iChangedEntries, pGrp2->EntryCount(), includeInUpdate ? "update" : "skip");

// success
return true;
Expand Down
5 changes: 3 additions & 2 deletions src/C4Update.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class C4UpdatePackageCore
char DestPath[_MAX_PATH + 1];
int32_t GrpUpdate;
int32_t UpGrpCnt; // number of file versions that can be updated by this package
bool AllowMissingTarget; // if true, missing target files are not considered an error
uint32_t GrpChks1[C4UP_MaxUpGrpCnt], GrpChks2;
uint32_t GrpContentsCRC1[C4UP_MaxUpGrpCnt], GrpContentsCRC2;

Expand All @@ -59,14 +60,14 @@ class C4UpdatePackage : public C4UpdatePackageCore
bool Execute(C4Group *pGroup);
static bool Optimize(C4Group *pGrpFrom, const char *strTarget);
CheckResult Check(C4Group *pGroup);
bool MakeUpdate(const char *strFile1, const char *strFile2, const char *strUpdateFile, const char *strName = nullptr);
bool MakeUpdate(const char *strFile1, const char *strFile2, const char *strUpdateFile, const char *strName, bool allowMissingTarget);

protected:
bool DoUpdate(C4Group *pGrpFrom, class C4GroupEx *pGrpTo, const char *strFileName);
bool DoGrpUpdate(C4Group *pUpdateData, class C4GroupEx *pGrpTo);
static bool Optimize(C4Group *pGrpFrom, class C4GroupEx *pGrpTo, const char *strFileName);

bool MkUp(C4Group *pGrp1, C4Group *pGrp2, C4GroupEx *pUpGr, bool *fModified);
bool MkUp(C4Group *pGrp1, C4Group *pGrp2, C4GroupEx *pUpGr, bool &includeInUpdate);

CStdFile Log;

Expand Down
4 changes: 2 additions & 2 deletions src/c4group_ng.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ bool ProcessGroup(const char *FilenamePar)
std::println(stderr, "Closing failed: {}", hGroup.GetError());
}
// generate
else if (!Upd.MakeUpdate(argv[iArg + 1], argv[iArg + 2], szFilename, argv[iArg + 3]))
else if (!Upd.MakeUpdate(argv[iArg + 1], argv[iArg + 2], szFilename, argv[iArg + 3], argv[iArg][2] == 'a'))
{
std::println(stderr, "Update generation failed.");
}
Expand Down Expand Up @@ -645,7 +645,7 @@ int main(int argc, char *argv[])
std::println(" -v View -l List -d Delete -r Rename -s Sort");
std::println(" -p Pack -u Unpack -x Explode");
std::println(" -k Print maker");
std::println(" -g [source] [target] [title] Make update");
std::println(" -g[a] [source] [target] [title] Make update [and allow missing target group when applying update]");
std::println(" -y[d] Apply update [and delete group file]");
std::println("");
std::println("Options: -v Verbose -r Recursive -p Prompt at end");
Expand Down

0 comments on commit 30ba2e1

Please sign in to comment.