GsfBlob, GsfClipData, and GsfDocMetaData second pass

This commit is contained in:
Matt Nadareski
2022-06-16 13:54:35 -07:00
parent c027b1798a
commit 4185367a49
3 changed files with 130 additions and 70 deletions

View File

@@ -23,6 +23,7 @@ using System;
namespace LibGSF
{
// TODO: Can this be made internal?
public class GsfBlob
{
#region Properties
@@ -54,6 +55,8 @@ namespace LibGSF
{
if (!((size > 0 && data_to_copy != null) || (size == 0 && data_to_copy == null)))
return null;
if (error != null)
return null;
byte[] data;
if (data_to_copy != null)

View File

@@ -27,6 +27,7 @@ namespace LibGSF
{
#region Enums
// TODO: Can this be made internal?
public enum GsfClipFormat
{
/// <summary>
@@ -66,6 +67,7 @@ namespace LibGSF
GSF_CLIP_FORMAT_UNKNOWN
}
// TODO: Can this be made internal?
public enum GsfClipFormatWindows
{
/// <summary>
@@ -96,6 +98,7 @@ namespace LibGSF
#endregion
// TODO: Can this be made internal?
public class GsfClipData
{
#region Properties
@@ -156,16 +159,12 @@ namespace LibGSF
/// <returns>A GsfClipFormatWindows value.</returns>
public GsfClipFormatWindows GetWindowsClipboardFormat(ref Exception error)
{
GsfClipFormatWindows format;
if (error == null)
return GsfClipFormatWindows.GSF_CLIP_FORMAT_WINDOWS_ERROR;
if (Format != GsfClipFormat.GSF_CLIP_FORMAT_WINDOWS_CLIPBOARD)
return GsfClipFormatWindows.GSF_CLIP_FORMAT_WINDOWS_ERROR;
long size = DataBlob.Size;
if (size < 4)
{
error = new InvalidDataException("The clip_data is in Windows clipboard format, but it is smaller than the required 4 bytes.");
@@ -173,30 +172,23 @@ namespace LibGSF
}
byte[] data = DataBlob.Data;
uint value = GSF_LE_GET_GUINT32(data, 0);
switch (value)
{
case (uint)GsfClipFormatWindows.GSF_CLIP_FORMAT_WINDOWS_METAFILE:
format = CheckFormatWindows(GsfClipFormatWindows.GSF_CLIP_FORMAT_WINDOWS_METAFILE, "Windows Metafile format", size, ref error);
break;
return CheckFormatWindows(GsfClipFormatWindows.GSF_CLIP_FORMAT_WINDOWS_METAFILE, "Windows Metafile format", size, ref error);
case (uint)GsfClipFormatWindows.GSF_CLIP_FORMAT_WINDOWS_DIB:
case 2: /* CF_BITMAP */
format = CheckFormatWindows(GsfClipFormatWindows.GSF_CLIP_FORMAT_WINDOWS_DIB, "Windows DIB or BITMAP format", size, ref error);
break;
return CheckFormatWindows(GsfClipFormatWindows.GSF_CLIP_FORMAT_WINDOWS_DIB, "Windows DIB or BITMAP format", size, ref error);
case (uint)GsfClipFormatWindows.GSF_CLIP_FORMAT_WINDOWS_ENHANCED_METAFILE:
format = CheckFormatWindows(GsfClipFormatWindows.GSF_CLIP_FORMAT_WINDOWS_ENHANCED_METAFILE, "Windows Enhanced Metafile format", size, ref error);
break;
return CheckFormatWindows(GsfClipFormatWindows.GSF_CLIP_FORMAT_WINDOWS_ENHANCED_METAFILE, "Windows Enhanced Metafile format", size, ref error);
default:
format = GsfClipFormatWindows.GSF_CLIP_FORMAT_WINDOWS_UNKNOWN;
break;
return GsfClipFormatWindows.GSF_CLIP_FORMAT_WINDOWS_UNKNOWN;
}
return format;
}
/// <summary>
@@ -227,7 +219,7 @@ namespace LibGSF
if (win_format == GsfClipFormatWindows.GSF_CLIP_FORMAT_WINDOWS_ERROR)
return null;
// gsf_clip_data_get_windows_clipboard_format() already did the size checks for us,
// GetWindowsClipboardFormat() already did the size checks for us,
// so we can jump to the offset right away without doing extra checks.
offset = GetWindowsClipboardDataOffset(win_format);
@@ -241,6 +233,10 @@ namespace LibGSF
return new ReadOnlySpan<byte>(data, (int)offset, (int)ret_size).ToArray();
}
#endregion
#region Utilities
private static void SetErrorMissingClipboardData(ref Exception error, string format_name, long at_least_size)
{
error = new InvalidDataException($"The clip_data is in {format_name}, but it is smaller than at least {at_least_size} bytes");
@@ -257,11 +253,9 @@ namespace LibGSF
// FIXME: does this have a PACKEDMETA in front as well, similar to GSF_CLIP_FORMAT_WINDOWS_METAFILE?
new FormatOffsetPair { Format = GsfClipFormatWindows.GSF_CLIP_FORMAT_WINDOWS_ENHANCED_METAFILE, Offset = 4 }
};
int num_pairs = pairs.Length;
int i;
for (i = 0; i < num_pairs; i++)
for (int i = 0; i < num_pairs; i++)
{
if (pairs[i].Format == format)
return pairs[i].Offset;

View File

@@ -31,6 +31,7 @@ using static LibGSF.GsfUtils;
namespace LibGSF
{
// TODO: Can this be made internal?
public class GsfDocProp
{
#region Properties
@@ -40,7 +41,7 @@ namespace LibGSF
public object Value { get; set; }
/// <summary>
/// Optionally NULL
/// Optionally null
/// </summary>
public string LinkedTo { get; set; }
@@ -104,9 +105,29 @@ namespace LibGSF
return old_val;
}
/// <summary>
/// A debugging utility to dump prop as text via Console
/// </summary>
/// <remarks>New in 1.14.2</remarks>
public void Dump()
{
if (Value is List<GsfDocProp> va)
{
for (int i = 0; i < va.Count; i++)
{
Console.WriteLine($"\t[{i}] = Name: {va[i].Name}, Value: {va[i].Value}, Link: {va[i].LinkedTo}, Ref: {va[i].RefCount}");
}
}
else
{
Console.WriteLine($"\t= {Value}");
}
}
#endregion
}
// TODO: Can this be made internal?
public class GsfDocMetaData
{
#region Properties
@@ -122,9 +143,7 @@ namespace LibGSF
/// </summary>
private GsfDocMetaData() { }
/// <returns>
/// A new metadata property collection
/// </returns>
/// <returns>A new metadata property collection</returns>
public static GsfDocMetaData Create() => new GsfDocMetaData();
#endregion
@@ -164,6 +183,84 @@ namespace LibGSF
Table[name] = docProp;
}
/// <summary>
/// If <paramref name="name"/> does not exist in the collection, do nothing. If @name does exist,
/// remove it and its value from the collection
/// </summary>
/// <param name="name">The non-null string name of the property</param>
public void Remove(string name)
{
if (name == null)
return;
if (!Table.ContainsKey(name))
return;
Table.Remove(name);
}
/// <returns>The property with <paramref name="name"/> in meta.</returns>
public GsfDocProp Steal(string name)
{
if (name == null)
return null;
if (!Table.ContainsKey(name))
return null;
GsfDocProp prop = Table[name];
if (prop != null)
Table.Remove(name);
return prop;
}
public void Store(GsfDocProp prop)
{
if (prop == null)
return;
if (prop != Lookup(prop.Name))
return;
Table[prop.Name] = prop;
}
/// <summary>
/// Iterate through each (key, value) pair in this collection
/// </summary>
/// <param name="func">The function called once for each element in the collection</param>
/// <param name="user_data">Any supplied user data</param>
public void ForEach(Action<string, GsfDocProp, object> func, object user_data)
{
if (Table.Count == 0)
return;
// Sort the pairs by property name in order to generate consistent files
List<KeyValuePair<string, GsfDocProp>> pairs = Table.ToList();
pairs.Sort((a, b) => DerefStrcmp(a.Key, b.Key));
for (int i = 0; i < pairs.Count; i++)
{
func(pairs[i].Key, pairs[i].Value, user_data);
}
}
/// <returns>The number of items in this collection</returns>
public int Size() => Table.Count;
/// <summary>
/// A debugging utility to dump the content of meta via Console
/// </summary>
public void Dump()
{
ForEach(PrintProperty, null);
}
#endregion
#region MS-OLE
/// <summary>
/// Read a stream formated as a set of MS OLE properties from <paramref name="input"/> and store the
/// results in <paramref name="accum"/>.
@@ -361,52 +458,6 @@ namespace LibGSF
return null;
}
/// <summary>
/// If <paramref name="name"/> does not exist in the collection, do nothing. If @name does exist,
/// remove it and its value from the collection
/// </summary>
/// <param name="name">The non-null string name of the property</param>
public void Remove(string name)
{
if (name == null)
return;
if (!Table.ContainsKey(name))
return;
Table.Remove(name);
}
/// <returns>The property with <paramref name="name"/> in meta.</returns>
public GsfDocProp Steal(string name)
{
if (name == null)
return null;
if (!Table.ContainsKey(name))
return null;
GsfDocProp prop = Table[name];
if (prop != null)
Table.Remove(name);
return prop;
}
public void Store(GsfDocProp prop)
{
if (prop == null)
return;
if (Table.ContainsKey(prop.Name) && Table[prop.Name] == prop)
return;
Table[prop.Name] = prop;
}
/// <returns>The number of items in this collection</returns>
public int Size() => Table.Count;
/// <summary></summary>
/// <param name="doc_not_component">A kludge to differentiate DocumentSummary from Summary</param>
/// <returns>True on success</returns>
@@ -539,6 +590,18 @@ namespace LibGSF
#region Utilities
private static int DerefStrcmp(string a, string b) => a.CompareTo(b);
private static void PrintProperty(string name, GsfDocProp prop, object user_data)
{
if (prop.LinkedTo != null)
Console.WriteLine($"prop '{name}' LINKED TO -> {prop.LinkedTo}");
else
Console.WriteLine($"prop '{name}'");
prop.Dump();
}
private int CodePageCharSize(int codepage) => (codepage == 1200 || codepage == 1201 ? 2 : 1);
private static int PropertyCompare(GsfMSOleMetaDataProp prop_a, GsfMSOleMetaDataProp prop_b)