summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMarkus Mittendrein <git@maxmitti.tk>2020-04-24 22:03:13 +0200
committerMarkus Mittendrein <git@maxmitti.tk>2020-04-24 22:03:13 +0200
commit578a2f3725b3ad221442763f450e8e239a5422d0 (patch)
tree61ad666be22b750fdcc78e71fdc01fb6d553ee82 /src
parent0e367485f950b2ab7b9bd1b6c5e4a9b5d328a5dc (diff)
downloadcc4group-578a2f3725b3ad221442763f450e8e239a5422d0.tar.gz
cc4group-578a2f3725b3ad221442763f450e8e239a5422d0.zip
Treat packed groups like normal subfolders when opening a folder containing packed groups
Diffstat (limited to 'src')
-rw-r--r--src/cc4group.c222
-rw-r--r--src/cc4group.h4
-rw-r--r--src/cppc4group.cpp6
-rw-r--r--src/cppc4group.hpp4
4 files changed, 191 insertions, 45 deletions
diff --git a/src/cc4group.c b/src/cc4group.c
index 76531f1..c8dde19 100644
--- a/src/cc4group.c
+++ b/src/cc4group.c
@@ -56,8 +56,10 @@ static bool cc4group_getEntryData(CC4Group* const this, const char* const entryP
typedef enum {
CC4Group_AllowedEntryTypes_File = 0x01,
CC4Group_AllowedEntryTypes_Directory = 0x02,
+ CC4Group_AllowedEntryTypes_HandleGroups = 0x04,
- CC4Group_AllowedEntryTypes_All = CC4Group_AllowedEntryTypes_File | CC4Group_AllowedEntryTypes_Directory
+ CC4Group_AllowedEntryTypes_NoGroupHandling = CC4Group_AllowedEntryTypes_File | CC4Group_AllowedEntryTypes_Directory,
+ CC4Group_AllowedEntryTypes_All = CC4Group_AllowedEntryTypes_File | CC4Group_AllowedEntryTypes_Directory | CC4Group_AllowedEntryTypes_HandleGroups
} CC4Group_AllowedEntryTypes;
struct list_GroupEntryList;
@@ -167,6 +169,8 @@ static GroupEntryList* cc4group_getChildren(CC4Group* const this, const C4GroupE
static C4GroupHeader* cc4group_getHeader(CC4Group* const this, const C4GroupEntryData* const entry);
static C4GroupEntryData* cc4group_createEntry(CC4Group* const this, const char* const path, C4GroupEntryData* const parent);
static C4GroupEntryData* cc4group_createDirectory(CC4Group* const this, const char* const path, C4GroupEntryData* const parent);
+static void cc4group_unreference(CC4Group* const this);
+static bool cc4group_getParentAndChildEntries(CC4Group* const this, const char* const path, const C4GroupEntryData* const inParent, const C4GroupEntryData** parentEntry, GroupEntryListEntry** const childEntry);
static char* cc4group_strerrorFormatter(int32_t const code, const char* const method, const char* const causer, void* const data)
{
@@ -1538,8 +1542,145 @@ static char* cc4group_pathCombine(const char* const firstPart, const char* secon
return result;
}
+static void* cc4group_memoryManagementOtherGroupStart(void* const data, size_t const size, void* const arg)
+{
+ (void)data;
+ (void)size;
+ ++((CC4Group*)arg)->referenceCounter;
+ return data;
+}
+
+static void cc4group_memoryManagementOtherGroupEnd(void* const data, void* const arg)
+{
+ (void)data;
+ cc4group_unreference(arg);
+}
+
+static const CC4Group_MemoryManagement_t otherGroupMemoryManagement = {
+ .start = cc4group_memoryManagementOtherGroupStart,
+ .end = cc4group_memoryManagementOtherGroupEnd,
+};
+
+static bool cc4group_deleteEntryFromParent(CC4Group* const this, GroupEntryListEntry* const deleteEntry, const C4GroupEntryData* const parent, bool recursive)
+{
+ if(deleteEntry->value.core.Directory)
+ {
+ if(!recursive)
+ {
+ SET_MESSAGE_ERROR("The desired entry is a subgroup but a non-recursive deletion was requested");
+ return false;
+ }
+
+ // if they are not loaded yet, there is no need to delete them
+ if(deleteEntry->value.children != NULL)
+ {
+ deleteChildren(deleteEntry->value.children);
+ }
+ }
+
+ if(deleteEntry->value.data != NULL)
+ {
+ cc4group_applyMemoryManagementEnd(deleteEntry->value.memoryManagement, deleteEntry->value.data);
+ }
+ if(deleteEntry->value.path)
+ {
+ free((void*)deleteEntry->value.path);
+ }
+
+ GroupEntryList* parentChildren = cc4group_getChildren(this, parent);
+ assert(parentChildren); // if there was an error, it should have really been catched already in cc4group_getParentAndChildEntries
+
+ GroupEntryListRemove(parentChildren, deleteEntry);
+ parent->header->Entries = GroupEntryListSize(parentChildren); // header is loaded already for the children
+
+ return true;
+}
+
+static bool cc4group_addOtherGroupContents(CC4Group* const this, C4GroupEntryData* const contentsRoot, CC4Group* const group, GroupEntryList* entries)
+{
+ if(entries == NULL)
+ {
+ SET_MESSAGE_ERROR("Could not retrieve children list of other group.");
+ return false;
+ }
+ CC4Group_MemoryManagement memoryMgmt = otherGroupMemoryManagement;
+ memoryMgmt.arg = group;
+ ForeachGroupEntry(entries)
+ {
+ C4GroupEntryData* newEntry;
+ if(entry->value.core.Directory)
+ {
+ newEntry = cc4group_createDirectory(this, entry->value.core.FileName, contentsRoot);
+ newEntry->children = GroupEntryListNew();
+ if(newEntry == NULL)
+ {
+ return false;
+ }
+ C4GroupHeader_setCreation(newEntry->header, entry->value.header->Creation);
+ C4GroupHeader_setOfficial(newEntry->header, entry->value.header->Official);
+ C4GroupHeader_setMaker(newEntry->header, entry->value.header->Maker);
+ if(!cc4group_addOtherGroupContents(this, newEntry, group, cc4group_getChildren(group, &entry->value)))
+ {
+ return false;
+ }
+ }
+ else
+ {
+ newEntry = cc4group_createEntry(this, entry->value.core.FileName, contentsRoot);
+ if(newEntry == NULL)
+ {
+ return false;
+ }
+ if(entry->value.data != NULL)
+ {
+ newEntry->data = entry->value.data;
+ if(!cc4group_applyMemoryManagementStart(memoryMgmt, (const uint8_t**)&newEntry->data, newEntry->core.Size))
+ {
+ assert(!"This must not happen.");
+ }
+ newEntry->memoryManagement = memoryMgmt;
+ }
+ }
+ newEntry->core.HasCRC = C4GroupEntryCore_NoCRC;
+ newEntry->core.Executable = entry->value.core.Executable;
+ newEntry->core.Modified = entry->value.core.Modified;
+ newEntry->core.Size = entry->value.core.Size;
+ }
+ return true;
+}
+
+static C4GroupEntryData* cc4group_addGroup(CC4Group* const this, CC4Group* const group, const char* const targetPath, C4GroupEntryData* const parent)
+{
+ assert(this);
+ C4GroupEntryData* const contentsRoot = cc4group_createDirectory(this, targetPath, parent);
+ if(!contentsRoot)
+ {
+ return NULL;
+ }
+ contentsRoot->children = GroupEntryListNew();
+ C4GroupHeader_setCreation(contentsRoot->header, group->root.header->Creation);
+ C4GroupHeader_setOfficial(contentsRoot->header, group->root.header->Official);
+ C4GroupHeader_setMaker(contentsRoot->header, group->root.header->Maker);
+ contentsRoot->core.Size = group->uncompressedSize;
+
+ if(cc4group_addOtherGroupContents(this, contentsRoot, group, group->root.children))
+ {
+ return contentsRoot;
+ }
+
+ const char* errorMessage = cc4group.getErrorMessage(this);
+ const C4GroupEntryData* deleteEntryparent;
+ GroupEntryListEntry* deleteEntry;
+ if(!cc4group_getParentAndChildEntries(this, targetPath, parent, &deleteEntryparent, &deleteEntry) && cc4group_deleteEntryFromParent(this, deleteEntry, deleteEntryparent, true))
+ {
+ cc4group_warn(this, "Loading contents from \"%s\" into this group \"%s\" failed with error: %s\n"
+ "Additionally, removing the directory which should have held the other group's contents failed. The error information stored in the group is about the failed deletion.", cc4group.getFullName(group), cc4group.getFullName(this), errorMessage);
+ }
+ return NULL;
+}
+
// takes over memory management of filePath
-static C4GroupEntryData* cc4group_addFileFromDisk(CC4Group* const this, const char* const filePath, const char* const targetPath, C4GroupEntryData* const parent)
+static C4GroupEntryData* cc4group_addFileFromDisk(CC4Group* const this, const char* const filePath, const char* const targetPath, C4GroupEntryData* const parent, bool handleGroup)
{
assert(this);
assert(filePath);
@@ -1554,6 +1695,27 @@ static C4GroupEntryData* cc4group_addFileFromDisk(CC4Group* const this, const ch
goto ret;
}
+ CC4Group* group = NULL;
+ if(handleGroup)
+ {
+ group = cc4group_new();
+ cc4group_setLazy(group, false);
+ if(!cc4group_openExisting(group, filePath))
+ {
+ cc4group_unreference(group);
+ }
+ else
+ {
+ C4GroupEntryData* contentsRoot = cc4group_addGroup(this, group, targetPath, parent);
+ if(contentsRoot != NULL)
+ {
+ free((void*)filePath);
+ cc4group_unreference(group);
+ return contentsRoot;
+ }
+ }
+ }
+
result = cc4group_createEntry(this, targetPath, parent);
if(result == NULL)
{
@@ -1678,7 +1840,7 @@ static bool cc4group_populateDirectoryFromDisk(CC4Group* const this, C4GroupEntr
}
else
{
- if(!cc4group_addFileFromDisk(this, directoryEntryPath, dirEntry->d_name, entry))
+ if(!cc4group_addFileFromDisk(this, directoryEntryPath, dirEntry->d_name, entry, true))
{
success = false;
break;
@@ -1780,6 +1942,11 @@ static void cc4group_delete(CC4Group* const this)
free(this->error.lastFormattedMessage);
}
+ if(this->root.path != NULL)
+ {
+ free((void*)this->root.path);
+ }
+
if(this->path != NULL)
{
free((void*)this->path);
@@ -2922,10 +3089,10 @@ static char* cc4group_splitParentAndChildPaths(char* const combinedPath, const c
}
}
-static bool cc4group_getParentAndChildEntries(CC4Group* const this, const char* const path, const C4GroupEntryData** parentEntry, GroupEntryListEntry** const childEntry)
+static bool cc4group_getParentAndChildEntries(CC4Group* const this, const char* const path, const C4GroupEntryData* const inParent, const C4GroupEntryData** parentEntry, GroupEntryListEntry** const childEntry)
{
bool error = false;
- GroupEntryListEntry* listEntry = cc4group_getChildListEntryByPath(this, path, &error, NULL);
+ GroupEntryListEntry* listEntry = cc4group_getChildListEntryByPath(this, path, &error, inParent);
if(error)
{
return false;
@@ -2950,42 +3117,12 @@ static bool cc4group_deleteEntry(CC4Group* const this, const char* const path, b
const C4GroupEntryData* parent;
GroupEntryListEntry* deleteEntry = NULL;
- if(!cc4group_getParentAndChildEntries(this, path, &parent, &deleteEntry))
+ if(!cc4group_getParentAndChildEntries(this, path, NULL, &parent, &deleteEntry))
{
return false;
}
- if(deleteEntry->value.core.Directory)
- {
- if(!recursive)
- {
- SET_MESSAGE_ERROR("The desired entry is a subgroup but a non-recursive deletion was requested");
- return false;
- }
-
- // if they are not loaded yet, there is no need to delete them
- if(deleteEntry->value.children != NULL)
- {
- deleteChildren(deleteEntry->value.children);
- }
- }
-
- if(deleteEntry->value.data != NULL)
- {
- cc4group_applyMemoryManagementEnd(deleteEntry->value.memoryManagement, deleteEntry->value.data);
- }
- if(deleteEntry->value.path)
- {
- free((void*)deleteEntry->value.path);
- }
-
- GroupEntryList* parentChildren = cc4group_getChildren(this, parent);
- assert(parentChildren); // if there was an error, it should have really been catched already in cc4group_getParentAndChildEntries
-
- GroupEntryListRemove(parentChildren, deleteEntry);
- parent->header->Entries = GroupEntryListSize(parentChildren); // header is loaded already for the children
-
- return true;
+ return cc4group_deleteEntryFromParent(this, deleteEntry, parent, recursive);
}
static C4GroupEntryData* cc4group_addEntryToDirectory(CC4Group* const this, C4GroupEntryData* const directory, const C4GroupEntryData* const entry)
@@ -3026,7 +3163,7 @@ static bool cc4group_renameEntry(CC4Group* const this, const char* const oldPath
const C4GroupEntryData* oldParent;
GroupEntryListEntry* entry = NULL;
- if(!cc4group_getParentAndChildEntries(this, oldPath, &oldParent, &entry))
+ if(!cc4group_getParentAndChildEntries(this, oldPath, NULL, &oldParent, &entry))
{
return false;
}
@@ -3161,15 +3298,14 @@ static bool cc4group_addFromDisk(CC4Group* const this, const char* const path, c
SET_MESSAGE_ERROR("The specified path doesn't match the specified allowed entry type");
return false;
}
-
switch(type)
{
case CC4Group_AllowedEntryTypes_File:
- return cc4group_addFileFromDisk(this, strdup(path), targetEntryPath, NULL) != NULL;
+ return cc4group_addFileFromDisk(this, strdup(path), targetEntryPath, NULL, allowedEntryTypes & CC4Group_AllowedEntryTypes_HandleGroups) != NULL;
case CC4Group_AllowedEntryTypes_Directory:
return cc4group_addDirectoryFromDisk(this, strdup(path), targetEntryPath, NULL);
- case CC4Group_AllowedEntryTypes_All:
- assert(!"All is not a valid type determined for the path; This code should never be reached");
+ case CC4Group_AllowedEntryTypes_All: case CC4Group_AllowedEntryTypes_NoGroupHandling: case CC4Group_AllowedEntryTypes_HandleGroups:
+ assert(!"Invalid type determined for the path; This code should never be reached");
return false;
}
@@ -3423,6 +3559,8 @@ CC4Group_API cc4group = {
.AllowedEntryTypes = {
.File = CC4Group_AllowedEntryTypes_File,
.Directory = CC4Group_AllowedEntryTypes_Directory,
+ .HandleGroups = CC4Group_AllowedEntryTypes_HandleGroups,
+ .NoGroupHandling = CC4Group_AllowedEntryTypes_NoGroupHandling,
.All = CC4Group_AllowedEntryTypes_All
},
diff --git a/src/cc4group.h b/src/cc4group.h
index 7e871a2..d06f636 100644
--- a/src/cc4group.h
+++ b/src/cc4group.h
@@ -192,7 +192,9 @@ typedef struct {
struct {
int File; // only a single regular file is allowed
int Directory; // only a directory is allowed, contents are handled recursively
- int All; // currently File | Directory
+ int HandleGroups; // groups are opened and contents are handled recursively
+ int NoGroupHandling; // currently File | Directory
+ int All; // currently File | Directory | HandleGroups
} const AllowedEntryTypes;
diff --git a/src/cppc4group.cpp b/src/cppc4group.cpp
index 2c69b98..b76767b 100644
--- a/src/cppc4group.cpp
+++ b/src/cppc4group.cpp
@@ -164,7 +164,11 @@ namespace {
{
result |= cc4group.AllowedEntryTypes.Directory;
}
- // All is handled by the above two
+ if(allowedEntryTypes & CppC4Group::AllowedEntryTypes::HandleGroups)
+ {
+ result |= cc4group.AllowedEntryTypes.HandleGroups;
+ }
+ // All and NoGroupHandling are handled by the above two
return result;
}
diff --git a/src/cppc4group.hpp b/src/cppc4group.hpp
index ae8b3b3..e8f7ba1 100644
--- a/src/cppc4group.hpp
+++ b/src/cppc4group.hpp
@@ -125,7 +125,9 @@ public:
enum class AllowedEntryTypes {
File = 0x1,
Directory = 0x2,
- All = File | Directory
+ HandleGroups = 0x4,
+ NoGroupHandling = File | Directory,
+ All = File | Directory | HandleGroups
};
// use this to set one of the predefined strategies