Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
ironfede committed Oct 2, 2024
2 parents 1cbae7b + 6d6a515 commit b4214ee
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 174 deletions.
204 changes: 70 additions & 134 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,14 +139,31 @@ 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 + "' ");
}

return new CFStream(CompoundFile, dirEntry);
}

bool Contains(string name, StgType type, out IDirectoryEntry directoryEntry)
{
IDirectoryEntry tmp = DirectoryEntry.Mock(name, type);
if (!Children.TryLookup(tmp, out IRBNode node) || node is not IDirectoryEntry de || de.StgType != type)
{
directoryEntry = null;
return false;
}

directoryEntry = de;
return true;
}

public bool ContainsStream(string streamName) => Contains(streamName, StgType.StgStream, out _);

public bool ContainsStorage(string storageName) => Contains(storageName, StgType.StgStorage, out _);

/// <summary>
/// Get a named <see cref="T:OpenMcdf.CFStream">stream</see> contained in the current storage if existing.
/// </summary>
Expand All @@ -171,22 +189,10 @@ public CFStream GetStream(string streamName)
{
CheckDisposed();

IDirectoryEntry tmp = DirectoryEntry.Mock(streamName, StgType.StgStream);

//if (children == null)
//{
// children = compoundFile.GetChildrenTree(SID);
//}
if (!Contains(streamName, StgType.StgStream, out IDirectoryEntry outDe))
throw new CFItemNotFound($"Cannot find item [{streamName}] within the current storage");


if (Children.TryLookup(tmp, out IRBNode outDe) && (((IDirectoryEntry)outDe).StgType == StgType.StgStream))
{
return new CFStream(CompoundFile, (IDirectoryEntry)outDe);
}
else
{
throw new CFItemNotFound("Cannot find item [" + streamName + "] within the current storage");
}
return new CFStream(CompoundFile, outDe);
}

/// <summary>
Expand All @@ -212,28 +218,14 @@ public CFStream GetStream(string streamName)
/// </example>
public bool TryGetStream(string streamName, out CFStream cfStream)
{
bool result = false;
cfStream = null;

try
if (CompoundFile.IsClosed || !Contains(streamName, StgType.StgStream, out IDirectoryEntry directoryEntry))
{
CheckDisposed();

IDirectoryEntry tmp = DirectoryEntry.Mock(streamName, StgType.StgStream);


if (Children.TryLookup(tmp, out IRBNode outDe) && (((IDirectoryEntry)outDe).StgType == StgType.StgStream))
{
cfStream = new CFStream(CompoundFile, (IDirectoryEntry)outDe);
result = true;
}
}
catch (CFDisposedException)
{
result = false;
cfStream = null;
return false;
}

return result;
cfStream = new CFStream(CompoundFile, directoryEntry);
return true;
}

/// <summary>
Expand All @@ -259,24 +251,8 @@ public bool TryGetStream(string streamName, out CFStream cfStream)
[Obsolete("Please use TryGetStream(string, out cfStream) instead.")]
public CFStream TryGetStream(string streamName)
{
CheckDisposed();

IDirectoryEntry tmp = DirectoryEntry.Mock(streamName, StgType.StgStream);

//if (children == null)
//{
// children = compoundFile.GetChildrenTree(SID);
//}


if (Children.TryLookup(tmp, out IRBNode outDe) && (((IDirectoryEntry)outDe).StgType == StgType.StgStream))
{
return new CFStream(CompoundFile, (IDirectoryEntry)outDe);
}
else
{
return null;
}
TryGetStream(streamName, out CFStream cfStream);
return cfStream;
}

/// <summary>
Expand All @@ -302,16 +278,10 @@ public CFStorage GetStorage(string storageName)
{
CheckDisposed();

IDirectoryEntry template = DirectoryEntry.Mock(storageName, StgType.StgInvalid);
if (!Contains(storageName, StgType.StgStorage, out IDirectoryEntry outDe))
throw new CFItemNotFound($"Cannot find item [{storageName}] within the current storage");

if (Children.TryLookup(template, out IRBNode outDe) && ((IDirectoryEntry)outDe).StgType == StgType.StgStorage)
{
return new CFStorage(CompoundFile, outDe as IDirectoryEntry);
}
else
{
throw new CFItemNotFound("Cannot find item [" + storageName + "] within the current storage");
}
return new CFStorage(CompoundFile, outDe);
}

/// <summary>
Expand All @@ -335,18 +305,8 @@ public CFStorage GetStorage(string storageName)
[Obsolete("Please use TryGetStorage(string, out cfStorage) instead.")]
public CFStorage TryGetStorage(string storageName)
{
CheckDisposed();

IDirectoryEntry template = DirectoryEntry.Mock(storageName, StgType.StgInvalid);

if (Children.TryLookup(template, out IRBNode outDe) && ((IDirectoryEntry)outDe).StgType == StgType.StgStorage)
{
return new CFStorage(CompoundFile, outDe as IDirectoryEntry);
}
else
{
return null;
}
TryGetStorage(storageName, out CFStorage cfStorage);
return cfStorage;
}

/// <summary>
Expand All @@ -371,27 +331,14 @@ public CFStorage TryGetStorage(string storageName)
/// </example>
public bool TryGetStorage(string storageName, out CFStorage cfStorage)
{
bool result = false;
cfStorage = null;

try
if (CompoundFile.IsClosed || !Contains(storageName, StgType.StgStorage, out IDirectoryEntry directoryEntry))
{
CheckDisposed();

IDirectoryEntry template = DirectoryEntry.Mock(storageName, StgType.StgInvalid);

if (Children.TryLookup(template, out IRBNode outDe) && ((IDirectoryEntry)outDe).StgType == StgType.StgStorage)
{
cfStorage = new CFStorage(CompoundFile, outDe as IDirectoryEntry);
result = true;
}
}
catch (CFDisposedException)
{
result = false;
cfStorage = null;
return false;
}

return result;
cfStorage = new CFStorage(CompoundFile, directoryEntry);
return true;
}

/// <summary>
Expand Down Expand Up @@ -438,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 @@ -524,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");
return throwOnError ? throw new CFItemNotFound($"Entry named [{entryName}] was not found") : false;

//if (foundObj.GetType() != typeCheck)
// throw new CFException("Entry named [" + entryName + "] has not the correct type");

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
30 changes: 1 addition & 29 deletions sources/OpenMcdf/CompoundFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1504,26 +1504,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].StartSect = 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 @@ -2413,13 +2393,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 Expand Up @@ -2486,8 +2459,7 @@ private void CloseCore(bool closeStream)

#region IDisposable Members


void IDisposable.Dispose()
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
Expand Down
Loading

0 comments on commit b4214ee

Please sign in to comment.