218 lines
7.9 KiB
C#
218 lines
7.9 KiB
C#
|
//----------------------------------------------------------------
|
|||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|||
|
//----------------------------------------------------------------
|
|||
|
namespace System.Activities.Debugger.Symbol
|
|||
|
{
|
|||
|
using System;
|
|||
|
using System.IO;
|
|||
|
using System.IO.Compression;
|
|||
|
using System.Runtime;
|
|||
|
using System.Runtime.Serialization;
|
|||
|
using System.Text;
|
|||
|
using System.Globalization;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Security.Cryptography;
|
|||
|
|
|||
|
// Represent debug symbol of a workflow tree (similar to pdb file).
|
|||
|
// It contains the absolute path of the xaml file and the location of each activity in the workflow tree.
|
|||
|
// This is used to instrument the workflow without having access to the original xaml file.
|
|||
|
public class WorkflowSymbol
|
|||
|
{
|
|||
|
public string FileName { get; set; }
|
|||
|
public ICollection<ActivitySymbol> Symbols { get; set; }
|
|||
|
|
|||
|
private byte[] checksum;
|
|||
|
public byte[] GetChecksum()
|
|||
|
{
|
|||
|
if (this.checksum == null)
|
|||
|
{
|
|||
|
return null;
|
|||
|
}
|
|||
|
return (byte[]) this.checksum.Clone();
|
|||
|
}
|
|||
|
|
|||
|
[Flags]
|
|||
|
internal enum EncodingFormat : byte
|
|||
|
{
|
|||
|
String = 0x76, // Format as well as cookie. String format is hidden from public.
|
|||
|
Binary = 0x77,
|
|||
|
Checksum = 0x80
|
|||
|
}
|
|||
|
|
|||
|
internal const EncodingFormat DefaultEncodingFormat = EncodingFormat.Binary;
|
|||
|
|
|||
|
public WorkflowSymbol()
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
// These constructors are private and used by Decode() method.
|
|||
|
|
|||
|
// Binary deserializer.
|
|||
|
WorkflowSymbol(BinaryReader reader, byte[] checksum)
|
|||
|
{
|
|||
|
this.FileName = reader.ReadString();
|
|||
|
int numSymbols = SymbolHelper.ReadEncodedInt32(reader);
|
|||
|
this.Symbols = new List<ActivitySymbol>(numSymbols);
|
|||
|
for (int i = 0; i < numSymbols; ++i)
|
|||
|
{
|
|||
|
this.Symbols.Add(new ActivitySymbol(reader));
|
|||
|
}
|
|||
|
this.checksum = checksum;
|
|||
|
}
|
|||
|
|
|||
|
// Decode from Base64 string.
|
|||
|
public static WorkflowSymbol Decode(string symbolString)
|
|||
|
{
|
|||
|
byte[] data = Convert.FromBase64String(symbolString);
|
|||
|
using (BinaryReader reader = new BinaryReader(new MemoryStream(data)))
|
|||
|
{
|
|||
|
byte[] checksum = null;
|
|||
|
EncodingFormat format = (EncodingFormat)reader.ReadByte();
|
|||
|
int payloadBytesCount = data.Length - sizeof(EncodingFormat);
|
|||
|
if (0 != (format & EncodingFormat.Checksum))
|
|||
|
{
|
|||
|
int bytesCount = SymbolHelper.ReadEncodedInt32(reader);
|
|||
|
checksum = reader.ReadBytes(bytesCount);
|
|||
|
payloadBytesCount -= SymbolHelper.GetEncodedSize(bytesCount);
|
|||
|
format &= (~EncodingFormat.Checksum);
|
|||
|
}
|
|||
|
switch (format)
|
|||
|
{
|
|||
|
case EncodingFormat.Binary:
|
|||
|
return ParseBinary(reader.ReadBytes(payloadBytesCount), checksum); // Compute the
|
|||
|
case EncodingFormat.String:
|
|||
|
return ParseStringRepresentation(reader.ReadString(), checksum);
|
|||
|
}
|
|||
|
}
|
|||
|
throw FxTrace.Exception.AsError(new SerializationException());
|
|||
|
}
|
|||
|
|
|||
|
// Serialization
|
|||
|
|
|||
|
// Encode to Base64 string
|
|||
|
public string Encode()
|
|||
|
{
|
|||
|
return Encode(WorkflowSymbol.DefaultEncodingFormat); // default format
|
|||
|
}
|
|||
|
|
|||
|
internal string Encode(EncodingFormat encodingFormat)
|
|||
|
{
|
|||
|
using (MemoryStream ms = new MemoryStream())
|
|||
|
{
|
|||
|
using (BinaryWriter writer = new BinaryWriter(ms))
|
|||
|
{
|
|||
|
if (this.checksum != null)
|
|||
|
{
|
|||
|
writer.Write((byte)(encodingFormat | EncodingFormat.Checksum));
|
|||
|
SymbolHelper.WriteEncodedInt32(writer, this.checksum.Length);
|
|||
|
writer.Write(this.checksum);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
writer.Write((byte)encodingFormat);
|
|||
|
}
|
|||
|
switch (encodingFormat)
|
|||
|
{
|
|||
|
case EncodingFormat.Binary:
|
|||
|
this.Write(writer);
|
|||
|
break;
|
|||
|
case EncodingFormat.String:
|
|||
|
writer.Write(this.ToString());
|
|||
|
break;
|
|||
|
default:
|
|||
|
throw FxTrace.Exception.AsError(new SerializationException());
|
|||
|
}
|
|||
|
// Need to copy to a buffer to trim excess capacity.
|
|||
|
byte[] buffer = new byte[ms.Length];
|
|||
|
Array.Copy(ms.GetBuffer(), buffer, ms.Length);
|
|||
|
return Convert.ToBase64String(buffer);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Binary deserializer
|
|||
|
static WorkflowSymbol ParseBinary(byte[] bytes, byte[] checksum)
|
|||
|
{
|
|||
|
using (BinaryReader reader = new BinaryReader(new MemoryStream(bytes)))
|
|||
|
{
|
|||
|
return new WorkflowSymbol(reader, checksum);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Binary serializer
|
|||
|
void Write(BinaryWriter writer)
|
|||
|
{
|
|||
|
writer.Write(this.FileName ?? string.Empty);
|
|||
|
if (this.Symbols != null)
|
|||
|
{
|
|||
|
SymbolHelper.WriteEncodedInt32(writer, this.Symbols.Count);
|
|||
|
foreach (ActivitySymbol actSym in this.Symbols)
|
|||
|
{
|
|||
|
actSym.Write(writer);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
SymbolHelper.WriteEncodedInt32(writer, 0);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// String encoding serialization.
|
|||
|
|
|||
|
// This is used for String encoding format.
|
|||
|
public override string ToString()
|
|||
|
{
|
|||
|
StringBuilder builder = new StringBuilder();
|
|||
|
builder.AppendFormat("{0}", this.FileName ?? string.Empty);
|
|||
|
if (this.Symbols != null)
|
|||
|
{
|
|||
|
foreach (ActivitySymbol symbol in Symbols)
|
|||
|
{
|
|||
|
builder.AppendFormat(";{0}", symbol.ToString());
|
|||
|
}
|
|||
|
}
|
|||
|
return builder.ToString();
|
|||
|
}
|
|||
|
|
|||
|
// Deserialization of string encoding format.
|
|||
|
static WorkflowSymbol ParseStringRepresentation(string symbolString, byte[] checksum)
|
|||
|
{
|
|||
|
string[] s = symbolString.Split(';');
|
|||
|
int numSymbols = s.Length - 1;
|
|||
|
ActivitySymbol[] symbols = new ActivitySymbol[numSymbols];
|
|||
|
for (int i = 0; i < numSymbols; ++i)
|
|||
|
{
|
|||
|
string[] symbolSegments = s[i + 1].Split(',');
|
|||
|
Fx.Assert(symbolSegments.Length == 5, "Invalid activity symbol");
|
|||
|
symbols[i] = new ActivitySymbol
|
|||
|
{
|
|||
|
QualifiedId = QualifiedId.Parse(symbolSegments[0]).AsByteArray(),
|
|||
|
StartLine = int.Parse(symbolSegments[1], CultureInfo.InvariantCulture),
|
|||
|
StartColumn = int.Parse(symbolSegments[2], CultureInfo.InvariantCulture),
|
|||
|
EndLine = int.Parse(symbolSegments[3], CultureInfo.InvariantCulture),
|
|||
|
EndColumn = int.Parse(symbolSegments[4], CultureInfo.InvariantCulture)
|
|||
|
};
|
|||
|
}
|
|||
|
|
|||
|
return new WorkflowSymbol
|
|||
|
{
|
|||
|
FileName = s[0],
|
|||
|
Symbols = symbols,
|
|||
|
checksum = checksum
|
|||
|
};
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
public bool CalculateChecksum()
|
|||
|
{
|
|||
|
this.checksum = null;
|
|||
|
if (!string.IsNullOrEmpty(this.FileName))
|
|||
|
{
|
|||
|
this.checksum = SymbolHelper.CalculateChecksum(this.FileName);
|
|||
|
}
|
|||
|
return (this.checksum != null);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|