Skip to content

Commit

Permalink
Add TryDelete
Browse files Browse the repository at this point in the history
Also, avoid redundant casts and lookups
  • Loading branch information
jeremy-visionaid committed Sep 30, 2024
1 parent b7af36b commit 6d6a515
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 70 deletions.
76 changes: 33 additions & 43 deletions sources/OpenMcdf/CFStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using RedBlackTree;
using System;
using System.Collections.Generic;
using System.Linq;

namespace OpenMcdf
{
Expand Down Expand Up @@ -138,7 +139,7 @@ public CFStream AddStream(string streamName)
}
catch (RBTreeException)
{
CompoundFile.ResetDirectoryEntry(dirEntry.SID);
dirEntry.Reset();

throw new CFDuplicatedItemException("An entry with name '" + streamName + "' is already present in storage '" + Name + "' ");
}
Expand Down Expand Up @@ -384,7 +385,7 @@ IDirectoryEntry cfo
}
catch (RBTreeDuplicatedItemException)
{
CompoundFile.ResetDirectoryEntry(cfo.SID);
cfo.Reset();
throw new CFDuplicatedItemException("An entry with name '" + storageName + "' is already present in storage '" + Name + "' ");
}

Expand Down Expand Up @@ -470,95 +471,84 @@ List<IRBNode> subStorages
/// <exception cref="T:OpenMcdf.CFDisposedException">Raised if trying to delete item from a closed compound file</exception>
/// <exception cref="T:OpenMcdf.CFItemNotFound">Raised if item to delete is not found</exception>
/// <exception cref="T:OpenMcdf.CFException">Raised if trying to delete root storage</exception>
public void Delete(string entryName)
public void Delete(string entryName) => DeleteCore(entryName, true);

public void TryDelete(string entryName) => DeleteCore(entryName, false);

bool DeleteCore(string entryName, bool throwOnError)
{
CheckDisposed();
if (CompoundFile.IsClosed)
return throwOnError ? throw new CFDisposedException("Owner Compound file has been closed and owned items have been invalidated") : false;

// Find entry to delete
IDirectoryEntry tmp = DirectoryEntry.Mock(entryName, StgType.StgInvalid);


Children.TryLookup(tmp, out IRBNode foundObj);

if (foundObj == null)
throw new CFItemNotFound("Entry named [" + entryName + "] was not found");

//if (foundObj.GetType() != typeCheck)
// throw new CFException("Entry named [" + entryName + "] has not the correct type");
return throwOnError ? throw new CFItemNotFound($"Entry named [{entryName}] was not found") : false;

if (((IDirectoryEntry)foundObj).StgType == StgType.StgRoot)
throw new CFException("Root storage cannot be removed");
IDirectoryEntry directoryEntry = (IDirectoryEntry)foundObj;
DeleteCore(directoryEntry);
return true;
}

void DeleteCore(IDirectoryEntry directoryEntry)
{
IRBNode altDel;
switch (((IDirectoryEntry)foundObj).StgType)
switch (directoryEntry.StgType)
{
case StgType.StgRoot:
throw new CFException("Root storage cannot be removed");

case StgType.StgStorage:

CFStorage temp = new CFStorage(CompoundFile, (IDirectoryEntry)foundObj);
CFStorage temp = new CFStorage(CompoundFile, directoryEntry);

// This is a storage. we have to remove children items first
foreach (IRBNode de in temp.Children)
foreach (IDirectoryEntry de in temp.Children.Cast<IDirectoryEntry>())
{
IDirectoryEntry ded = de as IDirectoryEntry;
temp.Delete(ded.Name);
temp.DeleteCore(de);
}

// ...then we Remove storage item from children tree...
Children.Delete(foundObj, out altDel);
Children.Delete(directoryEntry, out altDel);

// ...after which we need to rethread the root of siblings tree...
if (Children.Root != null)
DirEntry.Child = (Children.Root as IDirectoryEntry).SID;
else
DirEntry.Child = DirectoryEntry.NOSTREAM;
DirEntry.Child = Children.Root == null ? DirectoryEntry.NOSTREAM : ((IDirectoryEntry)Children.Root).SID;

// ...and remove directory (storage) entry

if (altDel != null)
{
foundObj = altDel;
directoryEntry = (IDirectoryEntry)altDel;
}

CompoundFile.InvalidateDirectoryEntry(((IDirectoryEntry)foundObj).SID);
directoryEntry.Reset();

break;

case StgType.StgStream:

// Free directory associated data stream.
CompoundFile.FreeAssociatedData((foundObj as IDirectoryEntry).SID);
CompoundFile.FreeAssociatedData(directoryEntry.SID);

// Remove item from children tree
Children.Delete(foundObj, out altDel);
Children.Delete(directoryEntry, out altDel);

// Rethread the root of siblings tree...
if (Children.Root != null)
DirEntry.Child = (Children.Root as IDirectoryEntry).SID;
else
DirEntry.Child = DirectoryEntry.NOSTREAM;
DirEntry.Child = Children.Root == null ? DirectoryEntry.NOSTREAM : ((IDirectoryEntry)Children.Root).SID;

// Delete operation could possibly have cloned a directory, changing its SID.
// Invalidate the ACTUALLY deleted directory.
if (altDel != null)
{
foundObj = altDel;
directoryEntry = (IDirectoryEntry)altDel;
}

CompoundFile.InvalidateDirectoryEntry(((IDirectoryEntry)foundObj).SID);
directoryEntry.Reset();

break;
}

//// Refresh recursively all SIDs (invariant for tree sorting)
//VisitedEntryAction action = delegate(CFSItem target)
//{
// if( ((IDirectoryEntry)target).SID>foundObj.SID )
// {
// ((IDirectoryEntry)target).SID--;
// }

// ((IDirectoryEntry)target).LeftSibling--;
//};
}

/// <summary>
Expand Down
27 changes: 0 additions & 27 deletions sources/OpenMcdf/CompoundFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1507,26 +1507,6 @@ internal List<Sector> GetSectorChain(int secID, SectorType chainType)

public CFSVersion Version => (CFSVersion)header.MajorVersion;

/// <summary>
/// Reset a directory entry setting it to StgInvalid in the Directory.
/// </summary>
/// <param name="sid">Sid of the directory to invalidate</param>
internal void ResetDirectoryEntry(int sid)
{
directoryEntries[sid].SetEntryName(string.Empty);
directoryEntries[sid].Left = null;
directoryEntries[sid].Right = null;
directoryEntries[sid].Parent = null;
directoryEntries[sid].StgType = StgType.StgInvalid;
directoryEntries[sid].StartSetc = DirectoryEntry.ZERO;
directoryEntries[sid].StorageCLSID = Guid.Empty;
directoryEntries[sid].Size = 0;
directoryEntries[sid].StateBits = 0;
directoryEntries[sid].StgColor = StgColor.Red;
directoryEntries[sid].CreationDate = new byte[8];
directoryEntries[sid].ModifyDate = new byte[8];
}

//internal class NodeFactory : IRBTreeDeserializer<CFItem>
//{

Expand Down Expand Up @@ -2416,13 +2396,6 @@ private static int LowSaturation(int i)
return i > 0 ? i : 0;
}

internal void InvalidateDirectoryEntry(int sid)
{
if (sid >= directoryEntries.Count)
throw new CFException("Invalid SID of the directory entry to remove");

ResetDirectoryEntry(sid);
}

internal void FreeAssociatedData(int sid)
{
Expand Down
21 changes: 21 additions & 0 deletions sources/OpenMcdf/DirectoryEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -455,5 +455,26 @@ public void AssignValueTo(RedBlackTree.IRBNode other)
d.storageCLSID = new Guid(storageCLSID.ToByteArray());
d.Child = Child;
}

/// <summary>
/// Reset a directory entry setting it to StgInvalid in the Directory.
/// </summary>
public void Reset()
{
// TODO: Delete IDirectoryEntry interface and use as DirectoryEntry
// member instead for improved performance from devirtualization
SetEntryName(string.Empty);
Left = null;
Right = null;
Parent = null;
StgType = StgType.StgInvalid;
StartSetc = ZERO;
StorageCLSID = Guid.Empty;
Size = 0;
StateBits = 0;
StgColor = StgColor.Red;
Array.Clear(CreationDate, 0, CreationDate.Length);
Array.Clear(ModifyDate, 0, ModifyDate.Length);
}
}
}
1 change: 1 addition & 0 deletions sources/OpenMcdf/IDirectoryEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,6 @@ internal interface IDirectoryEntry : IComparable, IRBNode
StgType StgType { get; set; }
Guid StorageCLSID { get; set; }
void Write(System.IO.Stream stream);
void Reset();
}
}

0 comments on commit 6d6a515

Please sign in to comment.