using System.Collections.Generic;
using System.Xml.Serialization;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
public static class XmlExtensions
const int DefaultChunkSize = 8000;
const int Base64BytesPerChunk = 3;
public static IEnumerable<XText> ToBase64XTextChunks(this Stream stream, int chunkSize = DefaultChunkSize)
return stream.ToBase64StringChunks(chunkSize).Select(s => new XText(s));
public static IEnumerable<XText> ToBase64XTextChunks(this IEnumerable<byte []> chunks, int chunkSize = DefaultChunkSize)
return chunks.ToBase64StringChunks(chunkSize).Select(s => new XText(s));
public static IEnumerable<string> ToBase64StringChunks(this Stream stream, int chunkSize = DefaultChunkSize)
throw new ArgumentNullException("stream");
if (chunkSize < 1 || chunkSize > int.MaxValue / Base64BytesPerChunk)
throw new ArgumentOutOfRangeException("chunkSize < 1 || chunkSize > int.MaxValue / Base64BytesPerChunk");
var buffer = new byte[Math.Max(300, Base64BytesPerChunk * DefaultChunkSize)];
return ToBase64StringChunksEnumerator(stream.ReadAllByteChunks(buffer), chunkSize);
public static IEnumerable<string> ToBase64StringChunks(this IEnumerable<byte []> chunks, int chunkSize = DefaultChunkSize)
throw new ArgumentNullException("chunks");
if (chunkSize < 1 || chunkSize > int.MaxValue / 3)
throw new ArgumentOutOfRangeException("chunkSize < 1 || chunkSize > int.MaxValue / 3");
return ToBase64StringChunksEnumerator(chunks, chunkSize);
static IEnumerable<string> ToBase64StringChunksEnumerator(this IEnumerable<ReadOnlyMemory<byte>> chunks, int chunkSize)
var buffer = new byte[Base64BytesPerChunk*chunkSize];
foreach (var chunk in chunks.ToFixedSizedChunks(buffer))
if (MemoryMarshal.TryGetArray(chunk, out var segment))
yield return Convert.ToBase64String(segment.Array, segment.Offset, segment.Count);
static IEnumerable<ReadOnlyMemory<byte>> ReadAllByteChunks(this Stream stream, byte [] buffer)
throw new ArgumentNullException("stream");
throw new ArgumentNullException("buffer");
throw new ArgumentException("buffer.Length < 1");
return ReadAllByteChunksEnumerator(stream, buffer);
static IEnumerable<ReadOnlyMemory<byte>> ReadAllByteChunksEnumerator(Stream stream, byte [] buffer)
while ((nRead = stream.Read(buffer, 0, buffer.Length)) > 0)
yield return new ReadOnlyMemory<byte>(buffer, 0, nRead);
public static partial class EnumerableExtensions
public static IEnumerable<ReadOnlyMemory<T>> ToFixedSizedChunks<T>(this IEnumerable<T []> chunks, T [] buffer)
throw new ArgumentNullException("chunks");
throw new ArgumentException("buffer.Length == 0");
return ToFixedSizedChunksEnumerator(chunks, buffer);
static IEnumerable<ReadOnlyMemory<T>> ToFixedSizedChunksEnumerator<T>(IEnumerable<ReadOnlyMemory<T>> chunks, Memory<T> buffer)
foreach (var chunk in chunks)
while (chunkIndex < chunk.Length)
int toCopy = Math.Min(buffer.Length - bufferIndex, chunk.Length - chunkIndex);
chunk.Slice(chunkIndex, toCopy).CopyTo(buffer.AsMemory().Slice(bufferIndex, toCopy));
if (bufferIndex == buffer.Length)
yield return new ReadOnlyMemory<T>(buffer, 0, bufferIndex);
if (bufferIndex > 0 || any)
yield return new ReadOnlyMemory<T>(buffer, 0, bufferIndex);
public static void Test()
var memory = new ReadOnlyMemory<char>(new char [] { 'a', 'b', 'c' });
Assert.That(MemoryMarshal.TryGetArray(memory, out seg));
Console.WriteLine(memory);
TestToXTextStringChunks(1, 8, 1, true);
TestToBase64XTextChunksRange();
TestToBase64StringChunks();
public static void TestToBase64XTextChunksRange()
TestToBase64XTextChunksRange(1, 8, 1);
TestToBase64XTextChunksRange(3, 8, 1);
TestToBase64XTextChunksRange(3, 11, 4);
TestToBase64XTextChunksRange(3);
TestToBase64XTextChunksRange(211);
public static void TestToBase64XTextChunksRange(int bufferSize)
TestToBase64StringChunksRange(bufferSize, 2003, 101);
public static void TestToBase64XTextChunksRange(int bufferSize, int byteRange, int chunkSize)
foreach (var length in Enumerable.Range(0, byteRange))
TestToXTextStringChunks(bufferSize, length, chunkSize);
static void TestToXTextStringChunks(int bufferSize, int length, int chunkSize, bool print = false)
var fileName = "Question77445872.bin";
var bytes = Enumerable.Range(0, length).Select(i => (byte)i).ToArray();
Console.WriteLine(JsonConvert.SerializeObject(bytes));
File.WriteAllBytes(fileName, bytes);
var result = new XElement("root");
var e = new XElement(itemProperty.Name);
using (var stream = File.OpenRead(fileName))
foreach (var text in stream.ToBase64XTextChunks(chunkSize))
Console.WriteLine(result.ToString(SaveOptions.DisableFormatting));
var expected = new XElement("root");
var eExpected = new XElement(itemProperty.Name);
eExpected.Add(Convert.ToBase64String(bytes));
expected.ToString(SaveOptions.DisableFormatting),
result.ToString(SaveOptions.DisableFormatting));
public static void TestToBase64StringChunks()
TestToBase64StringChunksRange(1, 8, 1);
TestToBase64StringChunksRange(3, 8, 1);
TestToBase64StringChunksRange(3, 11, 4);
TestToBase64StringChunksRange(3);
TestToBase64StringChunksRange(211);
public static void TestToBase64StringChunksRange(int bufferSize)
TestToBase64StringChunksRange(bufferSize, 2003, 101);
public static void TestToBase64StringChunksRange(int bufferSize, int byteRange, int chunkSize)
foreach (var length in Enumerable.Range(0, byteRange))
TestToBase64StringChunks(bufferSize, length, chunkSize);
static void TestToBase64StringChunks(int bufferSize, int length, int chunkSize)
var bytes = Enumerable.Range(0, length).Select(i => (byte)i).ToArray();
var chunks = bytes.Chunk(chunkSize);
Assert.That(bytes.SequenceEqual(chunks.SelectMany(b => b)),
"bytes.SequenceEqual(chunks.SelectMany(b => b))");
Assert.That(bytes.SequenceEqual(chunks.ToFixedSizedChunks(new byte [bufferSize]).SelectMany(p => p.Item1.Take(p.Item2))),
"chunks.ToFixedSizedChunks(new byte [bufferSize]).SelectMany(p => p.Item1.Take(p.Item2)))");
var base64chunks = chunks.ToBase64StringChunks(bufferSize);
var base64string = Convert.ToBase64String(bytes);
Assert.AreEqual(base64string, string.Concat(base64chunks));
public static partial class EnumerableExtensions
public static IEnumerable<T []> Chunk<T>(this IEnumerable<T> enumerable, int groupSize)
List<T> list = new List<T>(groupSize);
foreach (T item in enumerable)
if (list.Count == groupSize)
yield return list.ToArray();
yield return list.ToArray();
public static class XmlSerializationHelper
public static T LoadFromXml<T>(this string xmlString, XmlSerializer serial = null)
serial = serial ?? new XmlSerializer(typeof(T));
using (var reader = new StringReader(xmlString))
return (T)serial.Deserialize(reader);
public static string GetXml<T>(this T obj, XmlSerializer serializer = null, bool omitStandardNamespaces = false)
XmlSerializerNamespaces ns = null;
if (omitStandardNamespaces)
ns = new XmlSerializerNamespaces();
using (var textWriter = new StringWriter())
var settings = new XmlWriterSettings() { Indent = true };
using (var xmlWriter = XmlWriter.Create(textWriter, settings))
(serializer ?? new XmlSerializer(obj.GetType())).Serialize(xmlWriter, obj, ns);
return textWriter.ToString();
public static string GetOuterXml(this XmlNode node, bool indent = true)
using (var textWriter = new StringWriter())
var settings = new XmlWriterSettings
OmitXmlDeclaration = true,
using (var xmlWriter = XmlWriter.Create(textWriter, settings))
return textWriter.ToString();
public static class XmlAssert
public static void AreEqual(
Assert.IsTrue(XNode.DeepEquals(Normalize(expected), Normalize(actual)));
private static XElement Normalize(XElement element)
.OrderBy(a => a.Name.ToString()),
.OrderBy(a => a.Name.ToString())
.Select(e => Normalize(e)));
.OrderBy(a => a.Name.ToString()));
return new XElement(element.Name, element.Attributes()
.OrderBy(a => a.Name.ToString()), element.Value);
public static void Main()
Console.WriteLine("Environment version: {0}.", System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription);
Console.WriteLine("{0} version: {1}", typeof(Memory<byte>).Namespace, typeof(Memory<byte>).Assembly.FullName);
Console.WriteLine("Failed with unhandled exception: ");