added Privacy-Enhanced Mail encoding DataFormat (need to work on chaining feature)
This commit is contained in:
parent
eec2eea853
commit
e22b875b6a
@ -0,0 +1,159 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UniversalEditor.DataFormats.Text.Plain;
|
||||
using UniversalEditor.ObjectModels.Binary;
|
||||
using UniversalEditor.ObjectModels.Text.Plain;
|
||||
|
||||
namespace UniversalEditor.DataFormats.Binary.PEM
|
||||
{
|
||||
public class PEMDataFormat : PlainTextDataFormat
|
||||
{
|
||||
public string Signature { get; set; } = null;
|
||||
public int MaximumLineLength { get; set; } = 64;
|
||||
|
||||
private static DataFormatReference _dfr = null;
|
||||
protected override DataFormatReference MakeReferenceInternal()
|
||||
{
|
||||
if (_dfr == null)
|
||||
{
|
||||
_dfr = new DataFormatReference(typeof(PEMDataFormat));
|
||||
_dfr.Capabilities.Add(typeof(BinaryObjectModel), DataFormatCapabilities.All);
|
||||
_dfr.Capabilities.Add(typeof(PlainTextObjectModel), DataFormatCapabilities.All);
|
||||
_dfr.Title = "Privacy-Enhanced Mail encoding";
|
||||
_dfr.ExportOptions.Add(new CustomOptionText("Signature", "_Signature"));
|
||||
}
|
||||
return _dfr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method called BEFORE the LoadInternal method is called on the original <see cref="DataFormat" />'s subclass.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When inheriting from a
|
||||
/// <see cref="DataFormat" /> subclass (e.g. XMLDataFormat), you need to create a new instance of the appropriate <see cref="ObjectModel" /> that the
|
||||
/// subclass expects, and push that onto the <paramref name="objectModels"/> stack, i.e. <code>objectModels.Push(new MarkupObjectModel());</code> This is
|
||||
/// usually the only line of code in the overridden <see cref="BeforeLoadInternal" /> method's body.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// objectModels.Push(new BaseObjectModel()); // this is all we need to do
|
||||
/// </example>
|
||||
/// <param name="objectModels">The stack of <see cref="ObjectModel"/>s used by this <see cref="DataFormat" />.</param>
|
||||
protected override void BeforeLoadInternal(Stack<ObjectModel> objectModels)
|
||||
{
|
||||
base.BeforeLoadInternal(objectModels);
|
||||
objectModels.Push(new PlainTextObjectModel());
|
||||
}
|
||||
/// <summary>
|
||||
/// Method called AFTER the LoadInternal method is called on the original <see cref="DataFormat" />'s subclass.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When inheriting from a <see cref="DataFormat" /> subclass (e.g. XMLDataFormat), you need to first pop the <see cref="ObjectModel" /> that you pushed
|
||||
/// onto the <paramref name="objectModels"/> stack in your <see cref="BeforeLoadInternal" /> implementation, then pop the <see cref="ObjectModel" /> that
|
||||
/// your class expects to get passed. Now you can read data from the original <see cref="ObjectModel" /> and modify the second <see cref="ObjectModel" />.
|
||||
/// Because these objects are passed by reference, you do not need to push them back onto the stack for them to get properly loaded.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// BaseObjectModel bom = (objectModels.Pop() as BaseObjectModel); // base object model comes first
|
||||
/// MyVerySpecificObjectModel myOM = (objectModels.Pop() as MyVerySpecificObjectModel);
|
||||
///
|
||||
/// // populate MyVerySpecificObjectModel... and we're done. nothing else needs to be pushed back onto the stack.
|
||||
/// </example>
|
||||
/// <param name="objectModels">The stack of <see cref="ObjectModel"/>s used by this <see cref="DataFormat" />.</param>
|
||||
protected override void AfterLoadInternal(Stack<ObjectModel> objectModels)
|
||||
{
|
||||
base.AfterLoadInternal(objectModels);
|
||||
|
||||
PlainTextObjectModel ptom = (objectModels.Pop() as PlainTextObjectModel);
|
||||
|
||||
ObjectModel om = objectModels.Pop();
|
||||
|
||||
if (!ptom.Lines[0].StartsWith("-----", StringComparison.OrdinalIgnoreCase) && ptom.Lines[0].EndsWith("-----", StringComparison.OrdinalIgnoreCase))
|
||||
throw new InvalidDataFormatException("file does not begin with a -----{SIGNATURE}----- line");
|
||||
|
||||
if (!ptom.Lines[ptom.Lines.Count - 1].StartsWith("-----", StringComparison.OrdinalIgnoreCase) && ptom.Lines[ptom.Lines.Count - 1].EndsWith("-----", StringComparison.OrdinalIgnoreCase))
|
||||
throw new InvalidDataFormatException("file does not end with a -----{SIGNATURE}----- line");
|
||||
|
||||
string beginSignature = ptom.Lines[0].Substring(5 + 6, ptom.Lines[0].Length - 10 - 6);
|
||||
string endSignature = ptom.Lines[ptom.Lines.Count - 1].Substring(5 + 4, ptom.Lines[ptom.Lines.Count - 1].Length - 10 - 4);
|
||||
if (!endSignature.Equals(beginSignature))
|
||||
throw new InvalidDataFormatException(String.Format("begin signature '{0}' and end signature '{1}' do not match", beginSignature, endSignature));
|
||||
|
||||
Signature = beginSignature;
|
||||
|
||||
System.Text.StringBuilder sb = new System.Text.StringBuilder();
|
||||
for (int i = 1; i < ptom.Lines.Count - 1; i++)
|
||||
{
|
||||
sb.Append(ptom.Lines[i]);
|
||||
}
|
||||
|
||||
byte[] data = Convert.FromBase64String(sb.ToString());
|
||||
|
||||
if (om is BinaryObjectModel)
|
||||
{
|
||||
(om as BinaryObjectModel).Data = data;
|
||||
}
|
||||
else if (om is PlainTextObjectModel)
|
||||
{
|
||||
(om as PlainTextObjectModel).Text = System.Text.Encoding.UTF8.GetString(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ObjectModelNotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method called BEFORE the SaveInternal method is called on the original <see cref="DataFormat" />'s subclass.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// When inheriting from a <see cref="DataFormat" /> subclass (e.g. XMLDataFormat), you need to first pop the <see cref="ObjectModel" /> that your class
|
||||
/// expects to get passed, then create a new instance of the proper type of <see cref="ObjectModel" /> the base class is expecting. Now you can retrieve
|
||||
/// data from the <see cref="ObjectModel" /> that your class expects and properly format it for the <see cref="ObjectModel" /> the base class expects.
|
||||
/// When you're done, you need to push the newly-created <see cref="ObjectModel" /> onto the stack so that the underlying SaveInternal
|
||||
/// method will be able to see it.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// MyVerySpecificObjectModel myOM = (objectModels.Pop() as MyVerySpecificObjectModel);
|
||||
/// BaseObjectModel bom = new BaseObjectModel();
|
||||
///
|
||||
/// // populate BaseObjectModel...
|
||||
///
|
||||
/// objectModels.Push(bom); // aaand we're done
|
||||
/// </example>
|
||||
/// <param name="objectModels">The stack of <see cref="ObjectModel"/>s used by this <see cref="DataFormat" />.</param>
|
||||
protected override void BeforeSaveInternal(Stack<ObjectModel> objectModels)
|
||||
{
|
||||
base.BeforeSaveInternal(objectModels);
|
||||
|
||||
PlainTextObjectModel ptom = new PlainTextObjectModel();
|
||||
ptom.Lines.Add(String.Format("-----BEGIN{0}-----", (String.IsNullOrEmpty(Signature) ? String.Empty : " " + Signature.ToUpper())));
|
||||
|
||||
byte[] data = null;
|
||||
|
||||
ObjectModel om = objectModels.Pop();
|
||||
if (om is BinaryObjectModel)
|
||||
{
|
||||
data = (om as BinaryObjectModel).Data;
|
||||
}
|
||||
else if (om is PlainTextObjectModel)
|
||||
{
|
||||
data = System.Text.Encoding.UTF8.GetBytes((om as PlainTextObjectModel).Text);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ObjectModelNotSupportedException();
|
||||
}
|
||||
|
||||
string base64 = Convert.ToBase64String(data);
|
||||
|
||||
for (int i = 0; i < base64.Length; i += MaximumLineLength)
|
||||
{
|
||||
ptom.Lines.Add(base64.Substring(i, Math.Min(base64.Length - i, MaximumLineLength)));
|
||||
}
|
||||
|
||||
ptom.Lines.Add(String.Format("-----END{0}-----", (String.IsNullOrEmpty(Signature) ? String.Empty : " " + Signature.ToUpper())));
|
||||
|
||||
objectModels.Push(ptom);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -195,6 +195,7 @@
|
||||
<Compile Include="ObjectModels\Database\DatabaseTable.cs" />
|
||||
<Compile Include="ObjectModels\Database\DatabaseObjectModel.cs" />
|
||||
<Compile Include="ObjectModels\Project\IProjectItemContainer.cs" />
|
||||
<Compile Include="DataFormats\Binary\PEM\PEMDataFormat.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\UniversalEditor.Core\UniversalEditor.Core.csproj">
|
||||
@ -219,6 +220,7 @@
|
||||
<Folder Include="ObjectModels\BinaryGrammar\" />
|
||||
<Folder Include="ObjectModels\BinaryGrammar\GrammarItems\" />
|
||||
<Folder Include="ObjectModels\Database\" />
|
||||
<Folder Include="DataFormats\Binary\PEM\" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user