Skip to content

Commit

Permalink
Copy selection to RTF format
Browse files Browse the repository at this point in the history
  • Loading branch information
jlucansky committed Jul 25, 2020
1 parent 2d3d985 commit 6385aad
Show file tree
Hide file tree
Showing 20 changed files with 1,816 additions and 37 deletions.
28 changes: 19 additions & 9 deletions Source/Swiddler/Channels/SnifferChannel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,15 @@ private class Mediator : Channel
public Mediator(Session session) : base(session) { }
protected override void OnReceiveNotification(Packet packet) => throw new NotImplementedException();
public void Send(Packet packet) => NotifyObservers(packet); // write to session UI

public void Close(string reason)
{
HandleError(new Exception(reason));
}
public void ClosingDueFlag(string flag, IPEndPoint source)
{
Close($"Closing due to {flag} flag sent from {source}");
}
}

public SnifferChannel(Session session) : base(session) { }
Expand Down Expand Up @@ -118,12 +127,15 @@ protected override void StartOverride()

void StartAsAdmin()
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
if (!string.IsNullOrEmpty(Session.SettingsFileName))
{
if (MessageBox.Show(
"You don’t have permission to create raw sockets.\n\nDo you want to launch Swiddler as Administrator?",
"Access Denied", MessageBoxButton.YesNo, MessageBoxImage.Exclamation) == MessageBoxResult.Yes) Session.StartAsAdmin();
}));
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
if (MessageBox.Show(
"You don’t have permission to create raw sockets.\n\nDo you want to launch Swiddler as Administrator?",
"Access Denied", MessageBoxButton.YesNo, MessageBoxImage.Exclamation) == MessageBoxResult.Yes) Session.StartAsAdmin();
}));
}
}

void BeginReceive()
Expand Down Expand Up @@ -172,10 +184,8 @@ private void ReceiveCallback(IAsyncResult result)

mediator.Send(packet);

if (raw.Flags.HasFlag(TCPFlags.RST) || raw.Flags.HasFlag(TCPFlags.FIN))
{
mediator.Session.Stop();
}
if (raw.Flags.HasFlag(TCPFlags.RST)) mediator.ClosingDueFlag("RST", raw.Source);
if (raw.Flags.HasFlag(TCPFlags.FIN)) mediator.ClosingDueFlag("FIN", raw.Source);
}
}
}
Expand Down
8 changes: 5 additions & 3 deletions Source/Swiddler/IO/DataTransfer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ public class DataTransfer


readonly StorageHandle storage;
readonly Stream target;
readonly IDataTransferTarget target;

public DataTransfer(StorageHandle storage, Stream target)
public DataTransfer(StorageHandle storage, Stream target) : this (storage, new StreamTransferTarget(target)) { }

public DataTransfer(StorageHandle storage, IDataTransferTarget target)
{
this.storage = storage;
this.target = target;
Expand All @@ -41,7 +43,7 @@ void Copy(BlockReader reader, Func<IDataChunk, byte[]> payload)
while (reader.CurrentChunk != null && null != (data = payload(reader.CurrentChunk)))
{
if (data.Length > 0)
target.Write(data, 0, data.Length);
target.Write(reader.CurrentChunk, data);

reader.Read();
CancellationToken.ThrowIfCancellationRequested();
Expand Down
82 changes: 82 additions & 0 deletions Source/Swiddler/IO/IDataTransferTarget.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using Swiddler.Common;
using Swiddler.DataChunks;
using Swiddler.Utils.RtfWriter;
using System.IO;
using System.Text;

namespace Swiddler.IO
{
public interface IDataTransferTarget
{
void Write(IDataChunk chunk, byte[] data);
void Flush();
}

public class StreamTransferTarget : IDataTransferTarget
{
readonly Stream _stream;
public StreamTransferTarget(Stream stream) => _stream = stream;
public void Write(IDataChunk chunk, byte[] data) => _stream.Write(data, 0, data.Length);
public void Flush() => _stream.Flush();
}

public class RtfTransferTarget : IDataTransferTarget
{
RtfDocument _doc;
ColorDescriptor _inFg, _inBg, _outFg, _outBg;
Encoding _encoding { get; set; }

public RtfTransferTarget(RtfDocument doc, Encoding encoding)
{
_doc = doc;
_encoding = encoding;

doc.DefaultCharFormat.FontSize = 10;

_inFg = doc.createColor(new RtfColor(App.Current.Res.InboundFlowTextBrush.Color));
_inBg = doc.createColor(new RtfColor(App.Current.Res.InboundFlowBrush.Color));
_outFg = doc.createColor(new RtfColor(App.Current.Res.OutboundFlowTextBrush.Color));
_outBg = doc.createColor(new RtfColor(App.Current.Res.OutboundFlowBrush.Color));
}

public void Write(IDataChunk chunk, byte[] data)
{
var par = _doc.addParagraph();

par.setText(_encoding.GetString(data));

if (chunk is Packet packet)
{
if (packet.Flow == TrafficFlow.Inbound)
{
par.DefaultCharFormat.FgColor = _inFg;
par.DefaultCharFormat.BgColor = _inBg;
}
if (packet.Flow == TrafficFlow.Outbound)
{
par.DefaultCharFormat.FgColor = _outFg;
par.DefaultCharFormat.BgColor = _outBg;
}
}
}

public void Flush()
{
}
}

public class CompositeTransferTarget : IDataTransferTarget
{
IDataTransferTarget[] _targets;
public CompositeTransferTarget(params IDataTransferTarget[] targets) => _targets = targets;
public void Write(IDataChunk chunk, byte[] data)
{
foreach (var t in _targets) t.Write(chunk, data);
}
public void Flush()
{
foreach (var t in _targets) t.Flush();
}
}

}
2 changes: 1 addition & 1 deletion Source/Swiddler/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,4 @@
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

[assembly: AssemblyInformationalVersion("1.0.2")]
[assembly: AssemblyInformationalVersion("1.0.3")]
15 changes: 12 additions & 3 deletions Source/Swiddler/Rendering/FragmentView.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Swiddler.Common;
using Swiddler.IO;
using Swiddler.Utils.RtfWriter;
using System;
using System.Collections.Generic;
using System.Diagnostics;
Expand Down Expand Up @@ -77,7 +78,7 @@ public void CreateContent()
Session = CurrentSession,
Metrics = new FragmentViewMetrics()
{
Encoding = Encoding.Default,
Encoding = Encoding.GetEncoding(437), // IBM 437 (OEM-US)
Typeface = new Typeface("Lucida Console"),
FontSize = 14,
}
Expand Down Expand Up @@ -325,9 +326,17 @@ public void CopySelection(object sender, ExecutedRoutedEventArgs e)
{
using (var stream = new MemoryStream())
{
var transfer = new DataTransfer(CurrentSession.Storage, stream);
var rtf = new RtfDocument();
var target = new CompositeTransferTarget(new StreamTransferTarget(stream), new RtfTransferTarget(rtf, Metrics.Encoding));

var transfer = new DataTransfer(CurrentSession.Storage, target);
transfer.CopySelection(Content.SelectionStart, Content.SelectionEnd);
Clipboard.SetDataObject(Metrics.Encoding.GetString(stream.ToArray()), true);

DataObject data = new DataObject();
data.SetData(DataFormats.Text, Metrics.Encoding.GetString(stream.ToArray()));
data.SetData(DataFormats.Rtf, rtf.render());

Clipboard.SetDataObject(data);
}
}
catch (Exception ex)
Expand Down
24 changes: 24 additions & 0 deletions Source/Swiddler/Rendering/FragmentViewContent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@ internal void ComputeDpi()
FontChanged();
}

static readonly byte[] _sweep = Enumerable.Range(32, 256-32).Select(x => (byte)x).ToArray();
static readonly char[] _controlChars = new ushort[] { // Code Page 437 to Unicode mapping
0x0000, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022,
0x25D8, 0x0020, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C,
0x25BA, 0x25C4, 0x2195, 0x203C, 0x00B6, 0x00A7, 0x25AC, 0x21A8,
0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC }
.Select(x => (char)x).ToArray();

private GlyphTypeface _GlyphTypeface;
public GlyphTypeface GlyphTypeface
{
Expand All @@ -66,10 +74,26 @@ public GlyphTypeface GlyphTypeface
if (!Metrics.Typeface.TryGetGlyphTypeface(out _GlyphTypeface))
throw new NotSupportedException();

var map = _GlyphTypeface.CharacterToGlyphMap;
_glyphIndices = _controlChars.Concat(Metrics.Encoding.GetChars(_sweep)).Select(x => { map.TryGetValue(x, out var val); return val; }).ToArray();

return _GlyphTypeface;
}
}

ushort[] _glyphIndices;

/// <summary>
/// Convert bytes to glyph indices considering current GlyphTypeface and Encoding
/// </summary>
public ushort[] GetGlyphIndices(byte[] data, int start, int count)
{
var result = new ushort[count];
for (int i = 0; i < count; i++)
result[i] = _glyphIndices[data[start + i]];
return result;
}

void ComputeCharWidth()
{
if (LineHeight > 0)
Expand Down
17 changes: 6 additions & 11 deletions Source/Swiddler/Rendering/TextFragment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,23 @@ public override void OnRender(DrawingContext drawingContext, Rect bounds)
if (Length == 0)
return;

ushort[] glyphIndexes = new ushort[Length];
double[] advanceWidths = new double[Length];

GlyphTypeface glyphTypeface = View.Content.GlyphTypeface;

var advanceWidths = new double[Length];
var glyphIndices = View.Content.GetGlyphIndices(Data, Offset, Length);

double charWidth = View.Content.CharWidth;
double fontSize = View.Content.LineHeight - 2; // keep padding

for (int n = 0; n < Length; n++)
{
if (glyphTypeface.CharacterToGlyphMap.TryGetValue(Data[Offset + n], out ushort glyphIndex))
glyphIndexes[n] = glyphIndex;

advanceWidths[n] = charWidth;
}
for (int n = 0; n < Length; n++) advanceWidths[n] = charWidth;

var baseline = new Point(0, View.Content.SnapToPixelsY(glyphTypeface.Baseline * fontSize + 1.5, ceiling: true));

GlyphRun run = new GlyphRun(glyphTypeface,
bidiLevel: 0,
isSideways: false,
renderingEmSize: fontSize,
glyphIndices: glyphIndexes,
glyphIndices: glyphIndices,
baselineOrigin: baseline,
advanceWidths: advanceWidths,
glyphOffsets: null,
Expand Down
9 changes: 8 additions & 1 deletion Source/Swiddler/Swiddler.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
<Compile Include="Converters\CertificateValidityConverter.cs" />
<Compile Include="Converters\IntEnumConverter.cs" />
<Compile Include="Converters\AssignableTypeConverter.cs" />
<Compile Include="IO\IDataTransferTarget.cs" />
<Compile Include="IO\SyncedFileStream.cs" />
<Compile Include="Common\ValueException.cs" />
<Compile Include="Controls\ComboBoxEx.cs" />
Expand Down Expand Up @@ -149,10 +150,16 @@
<Compile Include="Utils\ControlExtensions.cs" />
<Compile Include="Utils\DateTimeExtensions.cs" />
<Compile Include="Utils\DependencyObjectExtensions.cs" />
<Compile Include="Utils\EncodingExtensions.cs" />
<Compile Include="Utils\Firewall.cs" />
<Compile Include="Utils\ImagingExtensions.cs" />
<Compile Include="Common\Injector.cs" />
<Compile Include="Utils\RtfWriter\RtfAbstract.cs" />
<Compile Include="Utils\RtfWriter\RtfBasics.cs" />
<Compile Include="Utils\RtfWriter\RtfBlockList.cs" />
<Compile Include="Utils\RtfWriter\RtfCharFormat.cs" />
<Compile Include="Utils\RtfWriter\RtfDocument.cs" />
<Compile Include="Utils\RtfWriter\RtfParagraph.cs" />
<Compile Include="Utils\RtfWriter\RtfUtility.cs" />
<Compile Include="Utils\TaskbarProgress.cs" />
<Compile Include="Utils\WindowExtensions.cs" />
<Compile Include="SocketSettings\SettingsBase.cs" />
Expand Down
57 changes: 57 additions & 0 deletions Source/Swiddler/Utils/RtfWriter/RtfAbstract.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
namespace Swiddler.Utils.RtfWriter
{
/// <summary>
/// Internal use only.
/// Objects that are renderable can emit RTF code.
/// </summary>
abstract public class RtfRenderable
{
/// <summary>
/// Internal use only.
/// Emit RTF code.
/// </summary>
/// <returns>RTF code</returns>
abstract public string render();
}

/// <summary>
/// Internal use only.
/// RtfBlock is a content block that cannot contain other blocks.
/// For example, an image is an RtfBlock because it cannot contain
/// other content block such as another image, a paragraph, a table,
/// etc.
/// </summary>
abstract public class RtfBlock : RtfRenderable
{
/// <summary>
/// How this block is aligned in its containing block.
/// </summary>
abstract public Align Alignment { get; set; }
/// <summary>
/// Default character formats.
/// </summary>
abstract public RtfCharFormat DefaultCharFormat { get; }
/// <summary>
/// When set to true, this block will be arranged in the beginning
/// of a new page.
/// </summary>
abstract public bool StartNewPage { get; set; }

protected string AlignmentCode()
{
switch (Alignment)
{
case Align.Left:
return @"\ql";
case Align.Right:
return @"\qr";
case Align.Center:
return @"\qc";
case Align.FullyJustify:
return @"\qj";
default:
return @"\qd";
}
}
}
}
Loading

0 comments on commit 6385aad

Please sign in to comment.